SWick

A table tennis power machine

MongoDB - UND-Verknüpfung bei Arrays
24th May 2012

Queries in MongoDB machen default eine UND-Operation. Wendet man dies jedoch auf Array Elemente an, kann dies falsche Ergebnisse liefern, wenn man den Query nicht richtig anwendet.

$ mongo
> db.people.insert({_id: "rms", first_name: "richard", last_name: "stallman"})
> db.people.insert({_id: "steve", first_name: "steve", last_name: "ballmer"})
>
> db.people.find()
{ "_id" : "rms", "first_name" : "richard", "last_name" : "stallman" }
{ "_id" : "steve", "first_name" : "steve", "last_name" : "ballmer" }
>
> db.people.find({first_name: "richard", last_name: "ballmer"})
>

Der letzte Query liefert keine Ausgabe, da es keinen Datensatz gibt, der als Vornamen richard und als Nachnamen ballmer hat.

Das Gleiche könnte man erwarten bei folgender Situation:

> db.tags.insert({_id: "foo", tags: ["tag1", "tag2", "tag3"]})
> db.tags.insert({_id: "bar", tags: ["tag4", "tag5", "tag6"]})
>
> db.tags.find()
{ "_id" : "foo", "tags" : [ "tag1", "tag2", "tag3" ] }
{ "_id" : "bar", "tags" : [ "tag4", "tag5", "tag6" ] }
>
> db.tags.find({tags: "tag1", tags: "tag4"}, {_id: true} )
{ "_id" : "bar" }
>
> db.tags.find({tags: "tag4", tags: "tag1"}, {_id: true} )
{ "_id" : "foo" }

Wie man sieht, erhält man ein Resultat, obwohl es keinen Datensatz gibt, in dem das Tag tag1 und tag4 vorkommt.

Es scheint, als überschreibt bei mehrmaliger Angabe des gleichen Keys, der letzte davon alle vorhergehenden:

Ein

db.tags.find({tags: "tag1", tags: "tag4"}, {_id: true} )

endet also als

db.tags.find({tags: "tag4"}, {_id: true} )

bzw.

db.tags.find({tags: "tag4", tags: "tag1"}, {_id: true} )

als

db.tags.find({tags: "tag1"}, {_id: true} )

Eine UND-Verknüpfung bei Array Elementen muss daher anders angeben werden:

> db.tags.find({ $and: [ {tags: "tag1" }, {tags: "tag4"} ] }, {_id: true} )
> 
> db.tags.find({ $and: [ {tags: "tag4" }, {tags: "tag1"} ] }, {_id: true} )
> 
> db.tags.find({ $and: [ {tags: "tag1" }, {tags: "tag3"} ] }, {_id: true} )
{ "_id" : "foo" }

Oder etwas eleganter:

> db.tags.find({ tags: { $all: ["tag1", "tag4"] } } , {_id: true} )
> 
> db.tags.find({ tags: { $all: ["tag1", "tag3"] } } , {_id: true} )
{ "_id" : "foo" }
Tags: db, mongodb, nosql.

"People said I should accept the world. Bullshit! I don't accept the world." -- Stallman