Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongodb Join on _id field from String to ObjectId

I have two collections

  1. User

    {    "_id" : ObjectId("584aac38686860d502929b8b"),    "name" : "John" } 
  2. Role

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

I want to join these collection based on the userId (in role collection) - _id ( in user collection).

I tried the below query:

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

This gives me expected results as long as i store userId as a ObjectId. When my userId is a string there are no results. Ps: I tried

foreignField: '_id'.valueOf()

and

foreignField: '_id'.toString()

. But no luck to match/join based on a ObjectId-string fields.

Any help will be appreciated.

like image 868
Kavya Mugali Avatar asked Dec 12 '16 03:12

Kavya Mugali


People also ask

Can _ID be a string MongoDB?

According to the Document page in the MongoDB manual: The _id field may contain values of any BSON data type, other than an array, regex, or undefined. So yes, you should be able to use a string as a document _id field.

How do I join two collections in MongoDB?

For performing MongoDB Join two collections, you must use the $lookup operator. It is defined as a stage that executes a left outer join with another collection and aids in filtering data from joined documents. For example, if a user requires all grades from all students, then the below query can be written: Students.

Is MongoDB ObjectId incremental?

MongoDB does not have out-of-the-box auto-increment functionality, like SQL databases. By default, it uses the 12-byte ObjectId for the _id field as the primary key to uniquely identify the documents.

What is localField and foreignField in MongoDB?

from : The collection to use for lookup in the same database. localField : The field in the primary collection that can be used as a unique identifier in the from collection. foreignField : The field in the from collection that can be used as a unique identifier in the primary collection.


2 Answers

You can use $toObjectId aggregation from mongodb 4.0 which converts String id to ObjectId

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

Or you can use $toString aggregation from mongodb 4.0 which converts ObjectId to String

db.role.aggregate([   { "$addFields": { "userId": { "$toString": "$_id" }}},   { "$lookup": {     "from": "user",     "localField": "userId",     "foreignField": "userId",     "as": "output"   }} ]) 
like image 163
Ashh Avatar answered Sep 20 '22 06:09

Ashh


This is not possible as of MongoDB 3.4. This feature has already been requested, but hasn't been implemented yet. Here are the corresponding tickets:

For now you'll have to store userId as ObjectId


EDIT

The previous tickets were fixed in MongoDB 4.0. You can now achieve this with the folowing query:

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

result:

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

try it online: mongoplayground.net/p/JoLPVIb1OLS

like image 36
felix Avatar answered Sep 20 '22 06:09

felix