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

Филтрирайте резултатите по стойността на последното поле за въвеждане на масив

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

Какво можете да направите сега

При условие, че вашите масиви вече са „сортирани“ чрез използване на $sort модификатор с $push , тогава вероятно можете да направите това:

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

Така че, докато partn,is_partner е "индексиран", това все още е доста ефективно, тъй като това първоначално условие на заявката може да бъде изпълнено с помощта на индекс. Частта, която не може, е $where клауза тук, която използва JavaScript оценка.

Но каква е тази втора част в $where което прави, е просто да "нарязва" последния елемент от масива и да тества неговата стойност на is_partner собственост, за да видите дали е вярно. Само ако това условие също е изпълнено, документът се връща.

Има и $slice проекционен оператор. Това прави същото при връщането на последния елемент от масива. Фалшивите съвпадения вече са филтрирани, така че това показва само последния елемент, когато е true.

В комбинация с индекса, както беше споменато, това трябва да бъде доста бързо, като се има предвид, че документите вече са избрани и условието на JavaScript просто филтрира останалите. Имайте предвид, че без друго поле със стандартно условие за заявка за съвпадение, $where клаузата не може да използва индекс. Така че винаги се опитвайте да използвате "пестеливо" с други условия на заявка.

Какво можете да направите в бъдеще

Next Up, въпреки че не е наличен към момента на писане, но със сигурност в близко бъдеще ще бъде $slice оператор за рамката за агрегиране. В момента това е в клона за разработка, но ето един поглед как работи:

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 ] }
  }}
])

Комбиниране на този $slice в рамките на $redact Етапът тук позволява документите да бъдат филтрирани с логическо условие, тествайки документа. В този случай $slice създава масив от единични елементи, който се изпраща на $ карта за да извлечете само единичния is_partner стойност (все още като масив). Тъй като това все още е масив от един елемент в най-добрия случай, другият тест е $anyElementTrue което прави това единичен булев резултат, подходящ за $cond .

$redact тук решава за този резултат дали да $$KEEP или $$PRUNE документа от резултатите. По-късно използваме $slice отново в проекта, за да върне само последния елемент от масива след филтрирането.

Това се оказва почти точно това, което прави версията на JavaScript, с изключение на това, че използва всички собствено кодирани оператори и следователно трябва да е малко по-бързо от алтернативата на JavaScript.

И двата формуляра връщат първия ви документ, както се очаква:

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

Голямата уловка тук и при двете е, че вашият масив трябва вече да е сортиран, така че последната дата да е първа. Без това ще ви трябва рамката за агрегиране за $sort масива, точно както правите сега.

Не е наистина ефективно, така че трябва да "сортирате предварително" вашия масив и да поддържате реда при всяка актуализация.

Като удобен трик, това всъщност ще пренареди всички елементи на масива във всички документи за събиране в един прост оператор:

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

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

Струва си да се обмисли, тъй като трябва да направи нещата много по-бързи.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Dropzone файлът не е напълно обработен при извикване на processFile(File)

  2. Как мога да извикам свойствата, които са в друга колекция в подмасив?

  3. Има ли еквивалентен инструмент като sql profiler за mongodb?

  4. Примерни оператори на MongoDB

  5. Как да превключите елемент в масив в mongoDB