MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Mongodb Query na podstawie liczby pól w rekordzie

Nadal nie jest to przyjemne zapytanie do uruchomienia, ale istnieje nieco bardziej nowoczesny sposób na wykonanie tego za pomocą $objectToArray i $redact

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

Gdzie $objectToArray zasadniczo przekształca obiekt w formę tablicy, podobnie jak kombinacja Object.keys() i .map() byłby w JavaScript.

To wciąż nie jest fantastyczny pomysł, ponieważ wymaga przeskanowania całej kolekcji, ale przynajmniej operacje na frameworku agregacji używają "kodu natywnego" w przeciwieństwie do interpretacji JavaScript, jak ma to miejsce przy użyciu $where .

Dlatego nadal zaleca się zmianę struktury danych i użycie naturalnej tablicy, a także przechowywanych właściwości „rozmiaru”, tam gdzie to możliwe, aby wykonać najbardziej efektywne operacje zapytań.

Tak, jest to możliwe, ale nie w najmilszy sposób. Powodem tego jest to, że zasadniczo używasz $where zapytanie operatora, które używa oceny JavaScript do dopasowania zawartości. Nie jest to najskuteczniejszy sposób, ponieważ nigdy nie można użyć indeksu i trzeba przetestować wszystkie dokumenty:

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

Spowoduje to wyszukanie warunku pasującego do „trzech” elementów, a następnie zwrócone zostaną tylko dwa z wymienionych dokumentów:

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

Lub dla "pięciu" pól lub więcej możesz zrobić to samo:

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

Tak więc argumenty tego operatora są de facto wyrażeniami JavaScript, które są oceniane na serwerze i zwracają gdzie true .

Bardziej wydajnym sposobem jest przechowywanie „liczby” elementów w samym dokumencie. W ten sposób możesz "indeksować" to pole, a zapytania są znacznie bardziej wydajne, ponieważ każdy dokument w zbiorze wybranym przez inne warunki nie musi być skanowany w celu określenia długości:

{_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}

Następnie, aby uzyskać dokumenty z "pięcioma" elementami, potrzebujesz tylko prostego zapytania:

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

To jest ogólnie najbardziej optymalna forma. Ale inną kwestią jest to, że ogólna struktura „obiektu”, z której możesz być zadowolony z ogólnej praktyki, nie jest czymś, z czym MongoDB „ogólnie dobrze się bawi”. Problemem jest „przemierzanie” elementów w obiekcie iw ten sposób MongoDB jest znacznie szczęśliwsze, gdy używasz „tablicy”. A nawet w tej formie:

{
    '_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 }
    ]
}

Więc jeśli faktycznie przełączysz się na taki format „tablicy”, możesz zrobić dokładnie długość tablicy z jedną wersją $size operator:

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

Ten operator może pracować dla dokładnie wartość dla długości tablicy, ponieważ jest to podstawowe określenie tego, co można zrobić za pomocą tego operatora. To, czego nie możesz zrobić, jest udokumentowane w meczu „nierówności”. W tym celu potrzebujesz „struktury agregacji” dla MongoDB, która jest lepszą alternatywą dla operacji JavaScript i 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
    }}
])

Więc to są zastępcy. Dostępna jest „natywna” metoda agregacji i typ tablicy. Ale jest dość dyskusyjne, że ocena JavaScript jest również "natywna" dla MongoDB, po prostu nie została zaimplementowana w kodzie natywnym.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Jak połączyć tablice z wielu dokumentów w MongoDB?

  2. Mongodb (v2.4.0) Agregat $match nie działa z zakresem dat

  3. Planowanie pracy w MongoDB

  4. MongoDB zapytanie $regex i potencjalne exploity

  5. Jak wstawiać obrazy w mongoDB za pomocą javy?