it-swarm.com.de

Abfrage von Dokumenten, bei denen die Arraygröße größer als 1 ist

Ich habe eine MongoDB-Sammlung mit Dokumenten im folgenden Format:

{
  "_id" : ObjectId("4e8ae86d08101908e1000001"),
  "name" : ["Name"],
  "zipcode" : ["2223"]
}
{
  "_id" : ObjectId("4e8ae86d08101908e1000002"),
  "name" : ["Another ", "Name"],
  "zipcode" : ["2224"]
}

Ich kann derzeit Dokumente abrufen, die einer bestimmten Arraygröße entsprechen: 

db.accommodations.find({ name : { $size : 2 }})

Dies gibt die Dokumente mit 2 Elementen im name-Array korrekt zurück. Ich kann jedoch keinen $gt-Befehl ausführen, um alle Dokumente zurückzugeben, bei denen das Feld name eine Arraygröße von mehr als 2 hat:

db.accommodations.find({ name : { $size: { $gt : 1 } }})

Wie kann ich alle Dokumente auswählen, deren name-Array größer als eins ist (vorzugsweise ohne die aktuelle Datenstruktur ändern zu müssen)?

522
emson

Update:

Für mongodb-Versionen 2.2+ eine effizientere Möglichkeit, dies durch @JohnnyHK in einem anderen answer .) Zu tun.


1.Verwenden von $ wo

db.accommodations.find( { $where: "this.name.length > 1" } );

Aber...

Javascript wird langsamer ausgeführt als die in .__ aufgeführten nativen Operatoren. Diese Seite ist aber sehr flexibel. Siehe die serverseitige Verarbeitungsseite für mehr Informationen.

2.Erstellen Sie das extra -Feld NamesArrayLength, aktualisieren Sie es mit der Länge des Namen-Arrays und verwenden Sie es in Abfragen:

db.accommodations.find({"NamesArrayLength": {$gt: 1} });

Es wird eine bessere Lösung sein und viel schneller arbeiten (Sie können einen Index dafür erstellen).

407
Andrew Orsich

In MongoDB 2.2+ gibt es eine effizientere Methode, da Sie jetzt numerische Array-Indizes in Abfrageobjektschlüsseln verwenden können.

// Find all docs that have at least a second name array element.
db.accommodations.find({'name.1': {$exists: true}})

Sie können diese Abfrage mit einem Index unterstützen, der einen Teilfilterausdruck verwendet (erfordert 3.2 oder höher):

db.accommodations.createIndex(
    {'name.1': 1},
    {partialFilterExpression: {'name.1': {$exists: true}}}
);
1104
JohnnyHK

Ich glaube, dies ist die schnellste Abfrage, die Ihre Frage beantwortet, da keine interpretierte $where-Klausel verwendet wird:

{$nor: [
    {name: {$exists: false}},
    {name: {$size: 0}},
    {name: {$size: 1}}
]}

Es bedeutet "alle Dokumente außer denen ohne Namen (entweder nicht vorhandenes oder leeres Array) oder nur einen Namen."

Prüfung:

> db.test.save({})
> db.test.save({name: []})
> db.test.save({name: ['George']})
> db.test.save({name: ['George', 'Raymond']})
> db.test.save({name: ['George', 'Raymond', 'Richard']})
> db.test.save({name: ['George', 'Raymond', 'Richard', 'Martin']})
> db.test.find({$nor: [{name: {$exists: false}}, {name: {$size: 0}}, {name: {$size: 1}}]})
{ "_id" : ObjectId("511907e3fb13145a3d2e225b"), "name" : [ "George", "Raymond" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225c"), "name" : [ "George", "Raymond", "Richard" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225d"), "name" : [ "George", "Raymond", "Richard", "Martin" ] }
>
111
Tobia

Sie können auch Aggregat verwenden:

db.accommodations.aggregate(
[
     {$project: {_id:1, name:1, zipcode:1, 
                 size_of_name: {$size: "$name"}
                }
     },
     {$match: {"size_of_name": {$gt: 1}}}
])

// Sie fügen dem Versanddokument "size_of_name" hinzu und filtern die Größe des Namens

46

Keines der oben genannten Dinge funktionierte für mich. Dies hat es so, ich teile es:

db.collection.find( {arrayName : {$exists:true}, $where:'this.arrayName.length>1'} )
33
Zloy Smiertniy

Versuche so etwas zu tun:

db.getCollection('collectionName').find({'ArrayName.1': {$exists: true}})

1 ist Zahl, wenn Sie einen Datensatz abrufen möchten, der größer als 50 ist, dann machen Sie ArrayName.50 Vielen Dank.

30
Aman Goel
db.accommodations.find({"name":{"$exists":true, "$ne":[], "$not":{"$size":1}}})
18
Yadvendar

Sie können $ expr (3,6-Mongo-Versionsoperator) verwenden, um Aggregationsfunktionen in regulären Abfragen zu verwenden. 

Vergleiche query operators vs aggregation comparison operators .

db.accommodations.find({$expr:{$gt:[{$size:"$name"}, 1]}})
15
Veeram

Ich habe diese Lösung gefunden, um Elemente zu finden, deren Feld größer als eine bestimmte Länge ist

db.allusers.aggregate([
  {$match:{username:{$exists:true}}},
  {$project: { count: { $size:"$locations.lat" }}},
  {$match:{count:{$gt:20}}}
])

Das erste $ match-Aggregat verwendet ein Argument, das für alle Dokumente gilt. Wenn leer, würde ich bekommen 

"errmsg" : "exception: The argument to $size must be an Array, but was of type: EOO"
11
Barrard

MongoDB 3.6 enthält $ expr https://docs.mongodb.com/manual/reference/operator/query/expr/

Sie können $ expr verwenden, um einen Ausdruck innerhalb eines $ -Patches auszuwerten oder zu suchen.

          {$match: {
                  $expr: {$gt: [{$size: "$yourArrayField"}, 0]}
              }
          }

oder finden

collection.find ({$ expr: {$ gte: [{$ size: "$ yourArrayField"}, 0]}});

0
Daniele Tassone