sql >> Databáze >  >> NoSQL >> MongoDB

Filtrovat výsledky podle hodnoty pole Poslední položka pole

Ujeté kilometry se mohou v tomto ohledu lišit a může se dobře ukázat, že „aktuálně“ proces, který sledujete, je přinejmenším „nejvhodnější“. Ale pravděpodobně to dokážeme efektivněji.

Co můžete nyní udělat

Za předpokladu, že jsou vaše pole již „seřazena“ pomocí $sort modifikátor s $push , pak pravděpodobně můžete udělat toto:

db.somedb.find(
  { 
    "partn.is_partner": true,
    "$where": function() {
      return this.partn.slice(-1)[0].is_partner == true;
    }
  },
  { "partn": { "$slice": -1 } }
)

Tedy pokud partn,is_partner je "indexovaný", je to stále docela efektivní, protože počáteční podmínka dotazu může být splněna pomocí indexu. Část, která nemůže, je $where klauzule zde, která používá hodnocení JavaScriptu.

Ale co ta druhá část v $where to, co dělá, je jednoduše "odříznout" poslední prvek z pole a otestovat jeho hodnotu is_partner vlastnost, abyste zjistili, zda je to pravda. Pouze pokud je splněna i tato podmínka, je dokument vrácen.

K dispozici je také $slice operátor projekce. To dělá totéž při vrácení posledního prvku z pole. Falešné shody jsou již filtrovány, takže se zobrazuje pouze poslední prvek, kde je pravda.

V kombinaci s indexem, jak bylo zmíněno, by to mělo být docela rychlé, protože dokumenty již byly vybrány a podmínka JavaScriptu pouze filtruje zbytek. Všimněte si, že bez dalšího pole s odpovídající standardní podmínkou dotazu $where klauzule nemůže používat index. Snažte se tedy vždy používat „střídmě“ s jinými podmínkami dotazu.

Co můžete dělat v budoucnu

Next Up, i když není v době psaní tohoto článku k dispozici, ale určitě v blízké budoucnosti bude $slice operátor pro agregační rámec. Toto je momentálně ve vývojové větvi, ale zde je náhled, jak to funguje:

db.somedb.aggregate([
  { "$match": { "partn.is_partner": true } },
  { "$redact": {
    "$cond": {
      "if": { 
        "$anyElementTrue": {
          "$map": {
            "input": { "$slice": ["$partn",-1] },
            "as": "el",
            "in": "$$el.is_partner"
          }
        }
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }},
  { "$project": {
      "partn": { "$slice": [ "$partn",-1 ] }
  }}
])

Kombinací tohoto $slice v rámci $redact fáze zde umožňuje filtrování dokumentů s logickou podmínkou, testování dokumentu. V tomto případě $slice vytvoří pole jednoho prvku, které se odešle do $ mapa za účelem extrahování jediného is_partner hodnotu (stále jako pole). Protože se v nejlepším případě stále jedná o pole s jedním prvkem, dalším testem je $anyElementTrue což z toho dělá singulární booleovský výsledek, vhodný pro $cond .

$redact zde rozhodne o tomto výsledku, zda $$KEEP nebo $$PRUNE dokument z výsledků. Později použijeme $slice znovu v projektu, aby se po filtrování vrátil pouze poslední prvek pole.

Ukázalo se, že je to v podstatě přesně to, co dělá verze JavaScriptu, s tou výjimkou, že používá všechny nativní kódované operátory, a proto by měla být o něco rychlejší než alternativa JavaScriptu.

Oba formuláře vrátí váš první dokument podle očekávání:

{
    "_id" : 0,
    "partn" : [
            {
                    "date" : ISODate("2015-07-28T00:59:14.963Z"),
                    "is_partner" : true
            },
            {
                    "date" : ISODate("2015-07-28T01:00:32.771Z"),
                    "is_partner" : false
            },
            {
                    "date" : ISODate("2015-07-28T01:15:29.916Z"),
                    "is_partner" : true
            },
            {
                    "date" : ISODate("2015-08-05T13:48:07.035Z"),
                    "is_partner" : false
            },
            {
                    "date" : ISODate("2015-08-05T13:50:56.482Z"),
                    "is_partner" : true
            }
    ]
}

Velkým úlovkem u obou je, že vaše pole již musí být seřazeno, takže poslední datum je první. Bez toho pak potřebujete agregační rámec pro $sort pole, stejně jako to děláte nyní.

Není to příliš efektivní, proto byste měli pole „předtřídit“ a udržovat pořadí při každé aktualizaci.

Jako praktický trik to ve skutečnosti změní pořadí všech prvků pole ve všech dokumentech kolekce jedním jednoduchým příkazem:

db.somedb.update(
    {},
    { "$push": { 
        "partn": { "$each": [], "$sort": { "date": 1 } }
    }},
    { "multi": true }
)

Takže i když „netlačíte“ nový prvek do pole a pouze aktualizujete vlastnost, vždy můžete použít tuto základní konstrukci, abyste zachovali uspořádání pole tak, jak chcete.

Stojí za zvážení, protože by to mělo věci mnohem rychleji urychlit.




  1. Vztah Loopback hasMany na mongodb nefunguje

  2. Časový limit připojení pro mongodb pomocí mongoose

  3. MongoError:nelze změnit _id dokumentu

  4. Počítejte výskyty ve vnořených dokumentech mongodb a udržovací skupině