J'ai une collection MongoDB avec des documents au format suivant:
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"name" : ["Name"],
"zipcode" : ["2223"]
}
{
"_id" : ObjectId("4e8ae86d08101908e1000002"),
"name" : ["Another ", "Name"],
"zipcode" : ["2224"]
}
Je peux actuellement obtenir des documents correspondant à une taille de tableau spécifique:
db.accommodations.find({ name : { $size : 2 }})
Cela renvoie correctement les documents avec 2 éléments dans le tableau name
. Cependant, je ne peux pas faire une commande $gt
pour renvoyer tous les documents où le champ name
a une taille de tableau supérieure à 2:
db.accommodations.find({ name : { $size: { $gt : 1 } }})
Comment sélectionner tous les documents avec un tableau name
de taille supérieure à un (de préférence sans modifier la structure de données actuelle)?
Mettre à jour:
Pour les versions de mongodb 2.2+ un moyen plus efficace de le faire décrit par @JohnnyHK dans un autre answer .
1.Utiliser $ où
db.accommodations.find( { $where: "this.name.length > 1" } );
Mais...
Javascript s'exécute plus lentement que les opérateurs natifs répertoriés sur cette page, mais est très flexible. Voir la page de traitement côté serveur pour plus d'informations.
2.Créez extra champ NamesArrayLength
, mettez-le à jour avec la longueur du tableau de noms, puis utilisez-le dans les requêtes:
db.accommodations.find({"NamesArrayLength": {$gt: 1} });
Ce sera une meilleure solution et fonctionnera beaucoup plus rapidement (vous pouvez créer un index dessus).
Il existe un moyen plus efficace de le faire dans MongoDB 2.2+ depuis que vous pouvez utiliser des index de tableau numériques dans les clés d'objet de requête.
// Find all docs that have at least a second name array element.
db.accommodations.find({'name.1': {$exists: true}})
Vous pouvez prendre en charge cette requête avec un index qui utilise une expression de filtre partielle (requiert 3.2+):
db.accommodations.createIndex(
{'name.1': 1},
{partialFilterExpression: {'name.1': {$exists: true}}}
);
Je pense que c’est la requête la plus rapide qui répond à votre question, car elle n’utilise pas de clause $where
interprétée:
{$nor: [
{name: {$exists: false}},
{name: {$size: 0}},
{name: {$size: 1}}
]}
Cela signifie "tous les documents sauf ceux sans nom (tableau non existant ou vide) ou avec un seul nom".
Tester:
> 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" ] }
>
Vous pouvez également utiliser l'agrégat:
db.accommodations.aggregate(
[
{$project: {_id:1, name:1, zipcode:1,
size_of_name: {$size: "$name"}
}
},
{$match: {"size_of_name": {$gt: 1}}}
])
// vous ajoutez "size_of_name" au document de transit et vous l'utilisez pour filtrer la taille du nom
Aucun de ce qui précède n'a fonctionné pour moi. Celui-ci l'a fait alors je le partage:
db.collection.find( {arrayName : {$exists:true}, $where:'this.arrayName.length>1'} )
Essayez de faire quelque chose comme ça:
db.getCollection('collectionName').find({'ArrayName.1': {$exists: true}})
1 est le nombre, si vous voulez récupérer un enregistrement supérieur à 50, faites ArrayName.50.
db.accommodations.find({"name":{"$exists":true, "$ne":[], "$not":{"$size":1}}})
Vous pouvez utiliser $ expr (opérateur de version 3.6 mongo) pour utiliser les fonctions d’agrégation dans une requête normale.
Comparer query operators
vs aggregation comparison operators
.
db.accommodations.find({$expr:{$gt:[{$size:"$name"}, 1]}})
J'ai trouvé cette solution, pour trouver des éléments avec un champ de tableau supérieur à une certaine longueur
db.allusers.aggregate([
{$match:{username:{$exists:true}}},
{$project: { count: { $size:"$locations.lat" }}},
{$match:{count:{$gt:20}}}
])
Le premier agrégat $ match utilise un argument qui vaut pour tous les documents. Si vide, j'aurais
"errmsg" : "exception: The argument to $size must be an Array, but was of type: EOO"
MongoDB 3.6 inclut $ expr https://docs.mongodb.com/manual/reference/operator/query/expr/
Vous pouvez utiliser $ expr pour évaluer une expression dans une correspondance $ ou find.
{$match: { $expr: {$gt: [{$size: "$yourArrayField"}, 0]} } }
ou trouver
collection.find ({$ expr: {$ gte: [{$ size: "$ yourArrayField"}, 0]}});