2011-07-17 3 views

Répondre

15

maintenant MongoDB (version 2.6) supports$size opération dans l'agrégation.

De la documentation:

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

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

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

ou

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

Je ne pense pas que vous pouvez utiliser un opérateur de taille $ exactement comme ceci avec $ group. $ size ne fait pas partie des [opérateurs d'agrégation] (http://docs.mongodb.org/manual/reference/operator/agrégation-group/). Au lieu de cela, vous pouvez utiliser la projection si vous n'avez pas besoin groupement: db.test.aggregate ({projet $: nombre: {$ size: "$ tags"}}) OU si vous avez besoin de regroupement , comme ceci: db.test.aggregate ({$ group: {_id: "$ userName", compte: {$ sum: {$ taille: "$ tags"}}}}) –

+0

intéressant que personne ne se soit plaint à ce sujet avant, merci – anvarik

+0

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

9

Actuellement, la seule façon de le faire semble utiliser db.eval, mais ce locks database for other operations.

Le moyen le plus rapide serait d'ajouter un champ supplémentaire qui stocke la longueur de la matrice et en le maintenant par $inc et $push opérations.

+0

Merci beaucoup.Oui, j'ai aussi pensé à garder la taille dans un champ séparé, mais j'espérais qu'il y aurait un meilleur moyen. –

15

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

Vous pouvez aussi le faire avec map/reduce (le canonical example) mais cela ne semble pas être être ce que vous voudriez.

Je ne suis pas sûr qu'il est 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 }}); 

Ce serait vous obtenez tous les documents avec 3 balises ...

+0

Merci pour le conseil de taille $, Justin. –

29

si le nom d'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

Merci. La question a été posée à l'époque, quand le cadre d'agrégation n'était pas disponible, mais c'est tout à fait logique maintenant. –

10

la réponse de xmm.dev peut être simplifiée: au lieu d'avoir co » champ interm unt », vous pouvez résumer directement dans le groupe $:

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

J'ai fait un petit travail autour comme je l'ai besoin d'interroger la taille du tableau et revenir si elle était supérieure à 0, mais pourrait être quelque chose de 1 à 3.

Voici ma solution était:

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

Cela renvoie essentiellement un document lorsque l'attribut existe et la taille est de 1, 2 ou 3. L'utilisateur peut ajouter des déclarations et augmentation si elles sont à la recherche d'un taille spécifique ou dans une gamme. Je sais que ce n'est pas parfait mais cela a fonctionné et était relativement rapide. J'ai seulement eu 1-3 tailles dans mon attribut donc cette solution a fonctionné.