Ich bin sicher, ich vermisse etwas sehr Grundlegendes in MongoDB-Abfragen, kann diese einfache Bedingung nicht bekommen.
Betrachten Sie diese Sammlung
> db.tests.find()
{ "_id" : ObjectId("..."), "name" : "Test1" , "deleted" : true}
{ "_id" : ObjectId("..."), "name" : "Test2" , "deleted" : false}
{ "_id" : ObjectId("..."), "name" : "Test3" }
Ich möchte einfach alle Elemente abfragen, die "nicht gelöscht" sind.
Ich weiß, wie ich das Element finde, bei dem das Flag "Gelöscht" auf "Wahr" gesetzt ist:
> db.tests.find({deleted:true})
{ "_id" : ObjectId("..."), "name" : "Test1" , "deleted" : true}
Aber wie finde ich alle Elemente, die NICHT sind "deleted"
(z. B. die obige Abfrage negieren, oder mit anderen Worten, alle Elemente, die entweder kein "deleted"
Feld oder einen Wert haben?false
Was ich durch Raten versucht habe (bitte nicht lachen ...)
> db.tests.find({$not : {deleted: true}})
(gibt keine Ergebnisse zurück)
> db.tests.find({$not : {$eq:{deleted:true}}})
Fehler: {"$ err": "ungültiger Operator: $ eq", "Code": 10068}
> db.tests.find({deleted:{$not: true}})
Fehler: {"$ err": "ungültige Verwendung von $ not", "Code": 13041}
> db.tests.find({deleted:{$not: {$eq:true}}})
Fehler: {"$ err": "ungültige Verwendung von $ not", "Code": 13034}
Was vermisse ich?
{deleted: 1}
.$in: [false,null]
schien aber zu funktionieren.Der Vollständigkeit halber können Sie dies auch mit
$in
folgenden Methoden tun :db.test.find({deleted: {$in: [null, false]}})
Durch die Aufnahme
null
in das Array werden die Dokumente abgerufen, in denen dasdeleted
Feld fehlt. Diese Abfrage kann einen Index für{deleted: 1}
die aktuelle Version 2.6.6 MongoDB verwenden.quelle
JohnnyHK hat die beste Antwort. Der
$in
Selektor ist die kürzeste und sauberste IMO.Dies wird auf genau "falsch" oder "nicht vorhanden" getestet. Und kann indiziert werden.
db.tests.find({$or:[{deleted:false},{deleted:{$exists:false}}]})
Ein Beispiel mit der Verwendung eines Index.
((function(){ print("creating collection 'testx' and inserting 50 trues, 50 falses, 50 non-existents"); db.testx.drop(); db.testx.ensureIndex({deleted:1}); for (var i=0;i<50;i++){ db.testx.insert({i:i,deleted:false}); }; for (var i=0;i<50;i++){ db.testx.insert({i:i,deleted:true}); }; for (var i=0;i<50;i++){ db.testx.insert({i:i}); }; var res0 = db.testx.find().explain(); var res1 = db.testx.find({deleted:false}).explain(); var res2 = db.testx.find({deleted:true}).explain(); var res3 = db.testx.find({deleted:{$exists:false}}).explain(); var res4 = db.testx.find({$or:[{deleted:false},{deleted:{$exists:false}}]}).explain(); var res5 = db.testx.find({$or:[{deleted:true},{deleted:{$exists:false}}]}).explain(); var res6 = db.testx.find({deleted:{$in:[false,null]}}).explain(); print("res0: all objects ("+res0["n"]+" found, "+res0["nscannedObjects"]+" scanned)"); print("res1: deleted is false ("+res1["n"]+" found, "+res1["nscannedObjects"]+" scanned)"); print("res2: deleted is true ("+res2["n"]+" found, "+res2["nscannedObjects"]+" scanned)"); print("res3: deleted is non-existent ("+res3["n"]+" found, "+res3["nscannedObjects"]+" scanned)"); print("res4: deleted is false or non-existent ("+res4["n"]+" found, "+res4["nscannedObjects"]+" scanned)"); print("res5: deleted is true or non-existent ("+res5["n"]+" found, "+res5["nscannedObjects"]+" scanned)"); print("res6: deleted is in [false,null] ("+res5["n"]+" found, "+res5["nscannedObjects"]+" scanned)"); })())
Dies sollte gedruckt werden
creating collection 'testx' and inserting 50 trues, 50 falses, 50 non-existents res0: all objects (150 found, 150 scanned) res1: deleted is false (50 found, 50 scanned) res2: deleted is true (50 found, 50 scanned) res3: deleted is non-existent (50 found, 50 scanned) res4: deleted is false or non-existent (100 found, 100 scanned) res5: deleted is true or non-existent (100 found, 100 scanned) res6: deleted is in [false,null] (100 found, 100 scanned)
quelle
Für den Fall, dass jemand dies in einer Aggregationspipeline anstelle von benötigt
find
, hat dies für mich funktioniertdb.getCollection('tests').aggregate([ // ...previous operations... { $addFields: { "deleted_conclusion": { $cond: { if:{ $ne: [ "$deleted", false ]}, then: { $cond: [ "$deleted", ":TRUE", ":FALSY"]}, else: ":FALSE" }}}} ])
Nachdem Sie das zusätzliche Feld hinzugefügt haben, können Sie mit den Pipeline-Phasen fortfahren und die Informationen erhalten, die Sie verpassen
quelle
Für den Fall, dass Sie nach einer Mongoid-Syntax suchen (ich verwende diese in einer Rails-App), habe ich Folgendes für die Benutzer eines Unternehmens entwickelt:
2.3.1 :042 > accepted_consent = org.users.active.where(:accepted_terms_and_conditions => true).count => 553 2.3.1 :043 > not_accepted_yet = org.users.active.where(:accepted_terms_and_conditions.ne => true).count => 6331 2.3.1 :044 > 6331+553 => 6884 2.3.1 :045 > org.users.active.count => 6884
quelle