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

Nalezení dvou prvků v poli dokumentů, které se objevují v daném pořadí

Pokud chcete v dotazu takové omezení, pak máte v podstatě dvě možnosti v závislosti na tom, co vaše verze MongoDB podporuje:

MongoDB 3.6

Nejlépe byste použili $expr "navíc" na jakékoli normální podmínky dotazu, abyste skutečně vybrali platné dokumenty:

var A = 10, B = 40;

Model.find({
  "subDocs.value": { "$all": [A, B] },
  "$expr": {
    "$lt": [
      { "$arrayElemAt": [
        "$subDocs.index",
        { "$indexOfArray": [ "$subDocs.value", A ]}
      ]},
      { "$arrayElemAt": [
        "$subDocs.index",
        { "$indexOfArray": [ "$subDocs.value", B ]}  
      ]}
    ]
  }
})

Nebo odpovídající "poslední" výskyt:

Model.find({
  "subDocs.value": { "$all": [A, B] },
  "$expr": {
    "$lt": [
      { "$arrayElemAt": [
        "$subDocs.index",
        { "$subtract": [
          { "$subtract": [{ "$size": "$subDocs.value" }, 1 ] },
          { "$indexOfArray": [ { "$reverseArray": "$subDocs.value" }, A ] }
        ]}
      ]},
      { "$arrayElemAt": [
        "$subDocs.index",
        { "$subtract": [
          { "$subtract": [{ "$size": "$subDocs.value" }, 1 ] },
          { "$indexOfArray": [ { "$reverseArray": "$subDocs.value" }, B ] }
        ]}
      ]}
    ]
  }
})

Starší verze

Totéž, ale bez nativních operátorů musíte použít JavaScript hodnocení $ kde :

var A = 10, B = 40;

Model.find({
  "subDocs.value": { "$all": [A, B] },
  "$where": `this.subDocs.find( e => e.value === ${A}).index
      < this.subDocs.find( e => e.value === ${B}).index`
})

Nebo odpovídající "poslední" výskyt:

Model.find({
  "subDocs.value": { "$all": [10,40] },
  "$where": `let arr = this.subDocs.reverse();
      return arr.find( e => e.value === ${A}).index
        > arr.find( e => e.value === ${B}).index`
})

Pokud byste to potřebovali v agregačním kanálu, pak byste použili $redact a podobná logika jako v prvním příkladu:

var A = 10, B = 40;

Model.aggregate([
  { "$match": { "subDocs.value": { "$all": [A, B] } } },
  { "$redact": {
    "$cond": {
      "if": {
        "$lt": [
          { "$arrayElemAt": [
            "$subDocs.index",
            { "$indexOfArray": [ "$subDocs.value", A ]}
          ]},
          { "$arrayElemAt": [
            "$subDocs.index",
            { "$indexOfArray": [ "$subDocs.value", B ]}  
          ]}
        ]
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

Stačí říci, že „logika porovnání“ není ve skutečnosti nativní pro samotné „výrazy operátorů dotazu“, takže jediná část, která „optimálně“ lze použít na index pomocí $all operátor dotazu ve všech případech. Základní zbývající logika ve skutečnosti platí „po“ vyhodnocení hlavního výrazu a „navíc“, aby nebyly vráceny žádné jiné výsledky než ty, které splňují výraz buď s $expr nebo $where .

Základní logikou každého z nich je v podstatě extrahovat hodnotu "index" vlastnost z "prvního" člena pole, která skutečně odpovídá příslušné hodnotě v "value" vlastnictví. Kde je toto "menší než", pak je podmínka true a to vyhovuje vracenému dokumentu.

Všimněte si tedy, že buď „vypočítané vyhodnocení“ odpovídá efektivitě operátorů dotazu, a bez použití „v kombinaci“ s jinými podmínkami operátora dotazu, které mají přístup k „indexu“, bude zahájeno „skenování celé kolekce“.

Ale celkový výsledek je určitě efektivnější než vracet všechny odpovídající položky do první podmínky dotazu a pak je odmítat na kurzoru "po" návratu z databáze.

Viz také dokumentaci pro $arrayElemAt , $indexOfArray , $lt a Array.find() pro JavaScript




  1. Najděte jeden dokument z celé kolekce s jednou konkrétní hodnotou vnořenou do více vložených dílčích dokumentů

  2. Chcete provést přírůstkovou zálohu pro mongodb. Vedení deníku? Oplog?

  3. MongoDB C# Index pole nebo indexování vnitřních položek polí

  4. Automaticky komprimovat odstraněný prostor v mongodb?