web-dev-qa-db-fra.com

Interrogation de la taille du tableau interne dans MongoDB

Considérez un document MongoDB dans la collection users:

{ username : 'Alex', tags: ['C#', 'Java', 'C++'] }

Existe-t-il un moyen d'obtenir la longueur du tableau tags du côté serveur (sans passer les balises au client)?

Je vous remercie!

40
Zaur Nasibov

Maintenant MongoDB (version 2.6) prend en charge$size opération en agrégation.

De la documentation:

{ <field>: { $size: <array> } }

Ce que vous voulez peut être accompli comme suit avec soit en utilisant ceci:

db.users.aggregate(
   [
      {
         $group: {
            _id: "$username",
            tags_count:  {$first: {$size: "$tags" }}
         }
      }
   ]
)

ou

db.users.aggregate(
   [
      {
         $project: {
            tags_count: {$size: "$tags"}
         }
      }
   ]
)
16
anvarik

si le nom d'utilisateur Alex est unique, vous pouvez utiliser le code suivant:

db.test.insert({username:"Alex", tags: ['C#', 'Java', 'C++'] });
db.test.aggregate(
  {$match: {username : "Alex"}}, 
  {$unwind: "$tags"},
  {$project: {count:{$add:1}}},
  {$group: {_id: null, number: {$sum: "$count" }}}
);
{ "result" : [ { "_id" : null, "number" : 3 } ], "ok" : 1 }
29
xmm.dev

Je pense qu'il pourrait être plus efficace de calculer le nombre de balises sur chaque sauvegarde (comme un champ séparé) en utilisant $ inc peut-être ou via un travail selon un calendrier.

Vous pouvez également le faire avec map/Reduce (le exemple canonique ) mais cela ne semble pas être ce que vous voudriez.

Je ne suis pas sûr qu'il soit possible de faire exactement ce que vous demandez, mais vous pouvez interroger tous les documents qui correspondent à une certaine taille avec $ size ...

> db.collection.find({ tags : { $size: 3 }});

Cela vous donnerait tous les documents avec 3 balises ...

16
Justin Jenkins

la réponse de xmm.dev peut être simplifiée: au lieu d'avoir le champ interm 'count', vous pouvez additionner directement dans $ group:

db.test.aggregate(
  {$match: {username : "Alex"}}, 
  {$unwind: "$tags"},
  {$group: {_id: null, number: {$sum: 1 }}}
) 
10
Volodymyr Metlyakov

Actuellement, la seule façon de le faire semble utiliser db.eval, mais ceci verrouille la base de données pour d'autres opérations .

Le moyen le plus efficace en termes de vitesse serait d'ajouter un champ supplémentaire qui stocke la longueur du tableau et de le maintenir par des opérations $ inc et $ Push .

9
plaes

J'ai fait un petit travail car j'avais besoin d'interroger la taille du tableau et de revenir si elle était supérieure à 0 mais pouvait être de 1 à 3.

Voici ma solution:

db.test.find($or : [{$field : { $exists : true, $size : 1}},
                    {$field : { $exists : true, $size : 2}},
                    {$field : { $exists : true, $size : 3}}, ])

Cela retourne essentiellement un document lorsque l'attribut existe et que la taille est 1, 2 ou 3. L'utilisateur peut ajouter plus d'instructions et d'incrémenter s'il recherche une taille spécifique ou dans une plage. Je sais que ce n'est pas parfait mais cela a fonctionné et a été relativement rapide. Je n'avais que 1 à 3 tailles dans mon attribut, donc cette solution a fonctionné.

0
kwoodson