41 votes

Interrogation de la taille d'un tableau interne dans MongoDB

Considérons un document MongoDB dans users collection :

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

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

Merci !

30voto

xmm.dev Points 381

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 }

1 votes

Merci. La question a été posée à l'époque où le cadre d'agrégation n'était pas disponible, mais elle est parfaitement logique maintenant.

19voto

anvarik Points 1614

Maintenant MongoDB (version 2.6) soutient $size l'opération d'agrégation.

Dans la documentation :

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

Ce que vous voulez peut être accompli comme suit avec l'un ou l'autre en utilisant ceci :

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

o

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

7 votes

Je ne pense pas que vous puissiez utiliser l'opérateur $size comme cela avec $group. $size ne fait pas partie des opérateurs d'agrégation . Au lieu de cela, vous pouvez utiliser la projection si vous n'avez pas besoin de regroupement : db.test.aggregate({$projet : count : {$size : "$tags"}}) OU si vous avez besoin de regroupement, quelque chose comme ceci : db.test.aggregate({$group : {_id : "$userName", count : {$sum : {$size : "$tags"}}}})

0 votes

Comment est-il possible d'obtenir quand j'ai quelque chose comme ceci : {nom d'utilisateur : 'Alex', tags : [['C#', 'Java', 'C++']] } Comment peut-on obtenir la longueur/taille des tags maintenant ?

0 votes

@rkatkam si tags est simplement un tableau de chaînes de caractères, vérifiez la réponse. S'il s'agit d'un tableau de tableaux, vous pouvez d'abord dérouler les balises.

16voto

Justin Jenkins Points 10501

Je pense qu'il serait plus efficace de calculer le nombre de balises pour chaque sauvegarde (en tant que champ séparé) en utilisant la méthode suivante $inc peut-être ou par le biais d'un travail sur un calendrier.

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

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 Taille ...

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

Vous obtiendrez tous les documents avec trois balises...

10voto

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

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

9voto

plaes Points 8535

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

La méthode la plus rapide consisterait à ajouter un champ supplémentaire qui stocke la longueur du tableau et le nom de l'utilisateur. le maintenir par $inc y $push opérations.

0 votes

Merci beaucoup. Oui, j'ai également pensé à conserver la taille dans un champ séparé, mais j'espérais qu'il y aurait une meilleure solution.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X