Въпреки че стоя зад коментарите, че не мисля, че начинът, по който формулирате въпроса си, всъщност е свързан с конкретен проблем, който имате, ще отида по някакъв начин, за да обясня идиоматичния SQL начин в решение тип MongoDB. Твърдя, че вашето действително решение би било различно, но не сте ни представили този проблем, а само SQL.
Така че разгледайте следните документи като примерен набор, като премахнете полетата _id в този списък за яснота:
{ "name" : "a", "type" : "b" }
{ "name" : "a", "type" : "c" }
{ "name" : "b", "type" : "c" }
{ "name" : "b", "type" : "a" }
{ "name" : "a", "type" : "b" }
{ "name" : "b", "type" : "c" }
{ "name" : "f", "type" : "e" }
{ "name" : "z", "type" : "z" }
{ "name" : "z", "type" : "z" }
Ако изпълним представения SQL върху същите данни, ще получим този резултат:
a|b
a|c
a|c
b|c
b|a
b|a
a|b
b|c
Можем да видим, че 2 документа не съвпадат, и след това да разработим логиката на SQL операцията. Така че другият начин да се каже е „Кои документи, на които е даден ключ от „име“, правят имат повече отедин възможна стойност в ключа "type".
Като се има предвид, че, използвайки mongo подход, можем да търсим елементи, които не съвпадат с даденото условие. Така че ефективнообратното от резултата:
db.sample.aggregate([
// Store unique documents grouped by the "name"
{$group: {
_id: "$name",
comp: {
$addToSet: {
name:"$name",
type: "$type"
}
}
}},
// Unwind the "set" results
{$unwind: "$comp"},
// Push the results back to get the unique count
// *note* you could not have done this with alongside $addtoSet
{$group: {
_id: "$_id",
comp: {
$push: {
name: "$comp.name",
type: "$comp.type"
}
},
count: {$sum: 1}
}},
// Match only what was counted once
{$match: {count: 1}},
// Unwind the array
{$unwind: "$comp"},
// Clean up to "name" and "type" only
{$project: { _id: 0, name: "$comp.name", type: "$comp.type"}}
])
Тази операция ще даде резултатите:
{ "name" : "f", "type" : "e" }
{ "name" : "z", "type" : "z" }
Сега, за да получим същия резултат като SQL заявката, ще вземем тези резултати и ще ги насочим към друга заявка:
db.sample.find({$nor: [{ name: "f", type: "e"},{ name: "z", type: "z"}] })
Което пристига като краен съответстващ резултат:
{ "name" : "a", "type" : "b" }
{ "name" : "a", "type" : "c" }
{ "name" : "b", "type" : "c" }
{ "name" : "b", "type" : "a" }
{ "name" : "a", "type" : "b" }
{ "name" : "b", "type" : "c" }
Така че това ще работи, но единственото нещо, което може да направи това непрактично, е къде броят на документите, които се сравняват е много голям, достигнахме работно ограничение за уплътняване на тези резултати до масив.
Малко страда и от използването на негативната в крайната операция за намиране, която ще принуди сканиране на колекцията. Но честно казано, същото може да се каже за SQL заявката, която използва същия отрицателен помещение.
Редактиране
Разбира се, това, което не споменах, е, че ако наборът от резултати върви обратното и вие отговаряте на още води до изключените елементи от съвкупността, след което просто обърнете логиката, за да получите ключовете, които искате. Просто променете $match както следва:
{$match: {$gt: 1}}
И това ще бъде резултатът, може би не действителните документи, но е резултат. Така че нямате нужда от друга заявка за съпоставяне на отрицателните случаи.
И в крайна сметка това беше моя грешка, защото бях толкова съсредоточен върху идиоматичния превод, че не прочетох последния ред във вашия въпрос, къде данаправите кажи, че си търсили документ.
Разбира се, внастоящема ако този размер на резултата е по-голям от 16 MB, значи сте блокирани. Поне до2.6 версия, където резултатите от операциите за агрегиране са курсор
, така че можете да повторите това като .find()
.
Също така въведено в 2.6 е $sizeкод>
оператор, който се използва за намиране на размера на масив в документа. Така че това би помогнало за премахването на втория $unwind
и $group
които се използват, за да се получи дължината на комплекта. Това променя заявката към по-бърза форма:
db.sample.aggregate([
{$group: {
_id: "$name",
comp: {
$addToSet: {
name:"$name",
type: "$type"
}
}
}},
{$project: {
comp: 1,
count: {$size: "$comp"}
}},
{$match: {count: {$gt: 1}}},
{$unwind: "$comp"},
{$project: { _id: 0, name: "$comp.name", type: "$comp.type"}}
])
А MongoDB 2.6.0-rc0 в момента е наличен, ако правите това само за лична употреба или разработка/тестване.
Морал на историята. Да можете направи го, Но тинаистина ли искам или трябвам да го направя по този начин? Тогава вероятно не и ако сте задали различен въпрос за конкретния бизнес случай, може да получите различен отговор. Но отново това може да е точно за това, което искате.
Забележка
Струва си да споменем, че когато погледнете резултатите от SQL, той погрешно ще се дублира няколко елемента поради другите налични опции за тип, ако не сте използвали DISTINCT
за тези стойности или по същество друго групиране. Но това е резултатът, получен от този процес с помощта на MongoDB.
За Александър
Това е резултатът от агрегата в обвивката от текущите версии 2.4.x:
{
"result" : [
{
"name" : "f",
"type" : "e"
},
{
"name" : "z",
"type" : "z"
}
],
"ok" : 1
}
Така че направете това, за да получите променлива, която да бъде предадена като аргумент на условието $nor във второто намиране, като това:
var cond = db.sample.aggregate([ .....
db.sample.find({$nor: cond.result })
И трябва да получите същите резултати. В противен случай се консултирайте с вашия шофьор.