I have two collections
User
{ "_id" : ObjectId("584aac38686860d502929b8b"), "name" : "John" }
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.
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.
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.
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.
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.
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" }} ])
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With