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

Mongodb Dotaz založený na počtu polí v záznamu

Stále to není pěkný dotaz na spuštění, ale existuje trochu modernější způsob, jak to udělat pomocí $objectToArray a $redact

db.collection.aggregate([
  { "$redact": {
    "$cond": {
      "if": {
        "$eq": [
          { "$size": { "$objectToArray": "$value" } },
          3
        ]
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

Kde $objectToArray v podstatě vnucuje objekt do tvaru pole, podobně jako kombinace Object.keys() a .map() by v JavaScriptu.

Stále to není fantastický nápad, protože to vyžaduje skenování celé kolekce, ale alespoň operace agregačního rámce používají "nativní kód" na rozdíl od interpretace JavaScriptu, jako je tomu v případě $where .

Stále je tedy obecně vhodné změnit datovou strukturu a tam, kde je to možné, používat přirozené pole a také uložené vlastnosti „velikost“, aby byly operace dotazů co nejúčinnější.

Ano, je to možné, ale ne tím nejlepším způsobem. Důvodem je, že v podstatě používáte $where dotaz operátora, který používá vyhodnocení JavaScriptu, aby odpovídal obsahu. Není to nejúčinnější způsob, protože to nikdy nemůže použít index a potřebuje otestovat všechny dokumenty:

db.collection.find({ "$where": "return Object.keys(this.value).length == 3" })

Toto hledá podmínku odpovídající "třem" prvkům, pak by byly vráceny pouze dva z vašich uvedených dokumentů:

{ "_id" : "number1", "value" : { "a" : 1, "b" : 2, "f" : 5 } }
{ "_id" : "number2", "value" : { "e" : 2, "f" : 114, "h" : 12 } }

Nebo pro "pět" polí nebo více můžete udělat totéž:

db.numbers.find({ "$where": "return Object.keys(this.value).length >= 5" })

Takže argumenty pro tento operátor jsou v podstatě příkazy JavaScriptu, které jsou na serveru vyhodnoceny tak, aby se vrátily tam, kde je true .

Efektivnějším způsobem je uložit „počet“ prvků do samotného dokumentu. Tímto způsobem můžete toto pole „indexovat“ a dotazy jsou mnohem efektivnější, protože každý dokument ve sbírce vybrané jinými podmínkami nemusí být pro určení délky skenován:

{_id:'number1', value:{'a':1, 'b':2, 'f':5} count: 3},
{_id:'number2', value:{'e':2, 'f':114, 'h':12}, count: 3},
{_id:'number3', value:{'i':2, 'j':22, 'z':12, 'za':111, 'zb':114}, count: 5}

K získání dokumentů s „pěti“ prvky pak potřebujete pouze jednoduchý dotaz:

db.collection.find({ "count": 5 })

To je obecně nejoptimálnější forma. Dalším bodem však je, že obecná struktura „Object“, se kterou byste mohli být spokojeni z obecné praxe, není něco, s čím si MongoDB obecně „dobře hraje“. Problémem je „procházení“ prvků v objektu a tímto způsobem je MongoDB mnohem šťastnější, když používáte „pole“. A to dokonce v této podobě:

{
    '_id': 'number1', 
    'values':[
        { 'key': 'a', 'value': 1 },
        { 'key': 'b', 'value': 2 }, 
        { 'key': 'f', 'value': 5 }
    ],
},
{
    '_id': 'number2', 
    'values':[
        { 'key': 'e', 'value': 2 }, 
        { 'key': 'f', 'value': 114 }, 
        { 'key': 'h', 'value': 12 }
    ],
},
{
    '_id':'number3', 
    'values': [
        { 'key': 'i', 'values': 2 }, 
        { 'key': 'j', 'values': 22 }, 
        { 'key': 'z'' 'values': :12 }, 
        { 'key': 'za', 'values': 111 },
        { 'key': 'zb', 'values': 114 }
    ]
}

Pokud tedy skutečně přepnete na formát „pole“, jako je tento, můžete provést přesné délka pole s jednou verzí $size operátor:

db.collection.find({ "values": { "$size": 5 } })

Tento operátor může pracovat pro přesné hodnotu pro délku pole, protože to je základní ustanovení toho, co lze s tímto operátorem dělat. To, co nemůžete udělat, je zdokumentováno v zápase „nerovnosti“. K tomu potřebujete „agregační rámec“ pro MongoDB, což je lepší alternativa k operacím JavaScript a mapReduce:

db.collection.aggregate([
    // Project a size of the array
    { "$project": {
        "values": 1,
        "size": { "$size": "$values" }
    }},
    // Match on that size
    { "$match": { "size": { "$gte": 5 } } },
    // Project just the same fields 
    {{ "$project": {
        "values": 1
    }}
])

To jsou tedy náhradníci. Pro agregaci a typ pole je k dispozici "nativní" metoda. Je však docela sporné, že hodnocení JavaScriptu je také „nativní“ pro MongoDB, jen proto není implementováno v nativním kódu.



  1. mongodb - Najít dokument s nejbližší celočíselnou hodnotou

  2. Mongo pořadí podle délky pole

  3. Uložení hlubokého adresářového stromu v databázi

  4. Jak vytvořit pole pole objektů schématu v Mongoose.js