Пробегът може да варира в зависимост от това и може да се окаже, че „в момента“ процесът, който следвате, се оказва поне „най-подходящ“. Но вероятно можем да направим по-ефективно.
Какво можете да направите сега
При условие, че вашите масиви вече са „сортирани“ чрез използване на $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 }
)
Така че дори и да не „вкарвате“ нов елемент в масив, а просто да актуализирате свойство, винаги можете да приложите тази основна конструкция, за да поддържате масива подреден както искате.
Струва си да се обмисли, тъй като трябва да направи нещата много по-бързи.