2017-09-15 4 views
0

J'essaie d'effectuer une requête en utilisant golang mgo pour obtenir des valeurs distinctes d'une jointure, je comprends que ce n'est peut-être pas le meilleur paradigme pour travailler avec Mongo.mgo avec l'agrégation et le groupage

Quelque chose comme ceci:

pipe := []bson.M{ 

    { 
     "$group": bson.M{ 
      "_id": bson.M{"user": "$user"}, 

     }, 
    }, 

    { 
     "$match": bson.M{ 
      "_id": bson.M{"$exists": 1}, 
      "user": bson.M{"$exists": 1}, 
      "date_updated": bson.M{ 
       "$gt": durationDays, 
      }, 
     }, 

    }, 

    { 
     "$lookup": bson.M{ 
      "from":   "users", 
      "localField": "user", 
      "foreignField": "_id", 
      "as":   "user_details", 
     }, 
    }, 
    { 
     "$lookup": bson.M{ 
      "from":   "organizations", 
      "localField": "organization", 
      "foreignField": "_id", 
      "as":   "organization_details", 
     }, 
    }, 

} 

err := d.Pipe(pipe).All(&result) 

Si je commente la section $group, la requête renvoie la jointure comme prévu.

Si je cours comme il est, je reçois NULL

Si je déplace le $group au fond du tube, je reçois une réponse de tableau avec des valeurs nulles

Est-il possible de faire faire une agrégation avec $group (avec l'objectif de simuler DISTINCT)?

Répondre

1

La raison pour laquelle vous obtenez NULL est que votre filtre $match filtre tous les documents après la phase $group.

Après votre première étape de $group les documents sont seulement comme exemple ci-dessous:

{"_id": { "user": "foo"}}, 
    {"_id": { "user": "bar"}}, 
    {"_id": { "user": "baz"}} 

Ils ne contient plus les autres domaines à savoir user, date_updated et organization. Si vous souhaitez conserver leurs valeurs, vous pouvez utiliser Group Accumulator Operator. En fonction de votre cas d'utilisation, vous pouvez également utiliser Aggregation Expression Variables

En tant qu'exemple utilisant mongo shell, utilisons $first operator qui sélectionnent la première occurrence. Cela peut sembler logique pour organization mais pas pour date_updated. Veuillez choisir un opérateur d'accumulateur plus approprié.

{"$group": { 
      "_id":"$user", 
      "date_updated": {"$first":"$date_updated"}, 
      "organization": {"$first":"$organization"} 
     } 
} 

Notez que ce qui précède remplace également {"_id":{"user":"$user"}} avec plus simple {"_id":"$user"}.

Ensuite, nous allons ajouter $project stage pour renommer le résultat du champ _id de l'opération de groupe à user. Portez également les autres champs sans modifications.

{"$project": { 
       "user": "$_id", 
       "date_updated": 1, 
       "organization": 1 
      } 
} 

Votre $match stage peut être simplifiée, en dressant la liste juste le filtre date_updated. Tout d'abord, nous pouvons supprimer _id car ce n'est plus pertinent jusqu'à présent dans le pipeline, et aussi si vous souhaitez vous assurer que vous ne traitez que les documents avec la valeur user, vous devez placer $match avant le $group. Voir Aggregation Pipeline Optimization pour plus.

Ainsi, tous les combinés ressemblera à quelque chose comme ci-dessous:

[ 
{"$group":{ 
      "_id": "$user", 
      "date_updated": { "$first": "$date_updated"}, 
      "organization": { $first: "$organization"} 
      } 
}, 
{"$project":{ 
       "user": "$_id", 
       "date_updated": 1, 
       "organization": 1 
      } 
}, 
{"$match":{ 
      "date_updated": {"$gt": durationDays } } 
}, 
{"$lookup":{ 
      "from": "users", 
      "localField": "user", 
      "foreignField": "_id", 
      "as": "user_details" 
      } 
}, 
{"$lookup":{ 
      "from": "organizations", 
      "localField": "organization", 
      "foreignField": "_id", 
      "as": "organization_details" 
      } 
} 
] 

(je sais que vous êtes au courant) Enfin, sur la base du schéma de base de données ci-dessus avec users et organizations collections, selon votre cas d'utilisation de l'application, vous pouvez réexaminer l'intégration de certaines valeurs. Vous pouvez trouver 6 Rules of Thumb for MongoDB Schema Design utile.

+0

merci pour une réponse et une explication si complètes! – avrono