web-dev-qa-db-fra.com

Mongodb Joint sur le champ _id de String à ObjectId

J'ai deux collections

  1. Utilisateur

             {
                 "_id" : ObjectId("584aac38686860d502929b8b"),
                 "name" : "John"
             }
    
  2. Rôle

     {
         "_id" : ObjectId("584aaca6686860d502929b8d"),
         "role" : "Admin",
         "userId" : "584aac38686860d502929b8b"  
     }
    

Je souhaite rejoindre cette collection basée sur le userId (dans role collection) - _id (dans user collection).

J'ai essayé la requête ci-dessous:

db.role.aggregate(
{
   $lookup:
   {
       from: 'user',
       localField: 'userId',
       foreignField: '_id',
       as: 'output'
   }
}
);

Cela me donne les résultats escomptés tant que je stocke userId en tant que ObjectId. Lorsque mon userId est une chaîne, il n'y a aucun résultat. Ps: j'ai essayé 

foreignField: '_id'.valueOf ()

et 

foreignField: '_id'.toString ()

. Mais pas de chance de faire correspondre/rejoindre basé sur un champs ObjectId-string.

Toute aide serait appréciée.

10
Kavya Mugali

Ceci n'est pas possible à partir de MongoDB 3.4. Cette fonctionnalité a déjà été demandée mais n'a pas encore été mise en œuvre. Voici les billets correspondants:

Pour l'instant, vous devrez stocker userId en tant que ObjectId

8
felix

Vous pouvez utiliser $toObjectId agrégation de mongodb 4.0 qui convertit String id en ObjectId

db.role.aggregate([
  { "$lookup": {
    "from": "user",
    "let": { "userId": "$_id" },
    "pipeline": [
      { "$addFields": { "userId": { "$toObjectId": "$userId" }}},
      { "$match": { "$expr": { "$eq": [ "$userId", "$$userId" ] } } }
    ],
    "as": "output"
  }}
])

Ou vous pouvez utiliser $toString agrégation de mongodb 4.0 qui convertit ObjectId en String 

db.role.aggregate([
  { "$addFields": { "userId": { "$toString": "$_id" }}},
  { "$lookup": {
    "from": "user",
    "localField": "userId",
    "foreignField": "userId",
    "as": "output"
  }}
])
9
Anthony Winzlet

Je pense que la réponse précédente a une erreur sur le cas '$ toObjectId'. L'instruction let s'applique à la collection de base de données sur laquelle la fonction aggregate est appelée (c'est-à-dire 'rôle') et non à la collection pointée par "de" (c'est-à-dire "utilisateur").

db.role.aggregate([
  { "$lookup": {
    "let": { "userObjId": { "$toObjectId": "$userId" } },
    "from": "user",
    "pipeline": [
      { "$match": { "$expr": { "$eq": [ "$_id", "$$userObjId" ] } } }
    ],
    "as": "userDetails"
  }}
])

Ou

db.role.aggregate([
  { "$project": { "userObjId": { "$toObjectId": "$userId" } } },
  { "$lookup": {
    "localField": "userObjId",
    "from": "user",
    "foreignField": "$_id",
    "as": "userDetails"
  }}
])

Et

db.user.aggregate([
  { "$project": { "userStrId": { "$toString": "$_id" }}},
  { "$lookup": {
    "localField": "userStrId",
    "from": "role",
    "foreignField": "userId",
    "as": "roleDetails"
  }}
])
0
Gary Wild