MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Mongodb Заявка въз основа на броя на полетата в запис

Все още не е приятна заявка за изпълнение, но има малко по-модерен начин да го направите чрез $objectToArray и $redact

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

Където $objectToArray основно принуждава обекта да се превърне във форма на масив, подобно на комбинация от Object.keys() и .map() би в JavaScript.

Това все още не е фантастична идея, тъй като изисква сканиране на цялата колекция, но поне операциите на рамката за агрегиране използват „местен код“ за разлика от интерпретацията на JavaScript, какъвто е случаят с $where .

Така че все още е препоръчително да промените структурата на данните и да използвате естествен масив, както и съхранени свойства на „размера“, където е възможно, за да направите най-ефективните операции за заявки.

Да, възможно е да се направи, но не по най-добрия начин. Причината за това е, че по същество използвате $where операторска заявка, която използва оценка на JavaScript, за да съответства на съдържанието. Не е най-ефективният начин, тъй като това никога не може да използва индекс и трябва да тества всички документи:

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

Това търси условието, съответстващо на "три" елемента, след което ще бъдат върнати само два от вашите изброени документи:

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

Или за "пет" полета или повече можете да направите почти същото:

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

Така че аргументите към този оператор са ефективно изрази на JavaScript, които се оценяват на сървъра, за да върнат къде true .

По-ефективен начин е да съхранявате "броя" на елементите в самия документ. По този начин можете да "индексирате" това поле и заявките са много по-ефективни, тъй като всеки документ в колекцията, избран от други условия, не е необходимо да се сканира, за да се определи дължината:

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

След това, за да получите документите с "пет" елемента, ви е необходима само простата заявка:

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

По принцип това е най-оптималната форма. Но друг момент е, че общата структура „Обект“, от която може да сте доволни от общата практика, не е нещо, с което MongoDB „играе добре“ като цяло. Проблемът е "преминаване" на елементи в обекта и по този начин MongoDB е много по-щастлив, когато използвате "масив". И дори в тази форма:

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

Така че, ако действително превключите към формат "масив" като този, тогава можете да направите точен дължина на масив с една версия на $size оператор:

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

Този оператор може да работи за точна стойност за дължина на масив, тъй като това е основно условие за това, което може да се направи с този оператор. Това, което не можете да направите, е документирано в съвпадение на „неравенство“. За целта се нуждаете от „рамката за агрегиране“ за MongoDB, която е по-добра алтернатива на JavaScript и операциите 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
    }}
])

Така че това са алтернативите. Има "роден" метод, наличен за агрегиране и тип масив. Но е доста спорно, че оценката на JavaScript също е „местна“ за MongoDB, просто не е внедрена в собствен код.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Прегледайте Mongo Collection и актуализирайте поле във всеки документ

  2. ConversionFailedException:запазване на DBObject, но извличането връща LinkedHashMap<?, ?>

  3. Битката на базите данни NoSQL - Сравняване на MongoDB и Cassandra

  4. вземете всички документи с максимална стойност, като използвате агрегиране в mongodb

  5. Groovy не можа да намери съвпадащ конструктор?