How can I lookup into field in the array in mongodb - mongodb

{
"id": "1",
"label" : "alex",
"children" : [
{
"id" : "rJqS8aW-W"
},
{
"id" : "SkF8UaW-W"
}
],
}
{
"label" : "felix",
"id" : "rJqS8aW-W",
"children" : [
{
"id" : "S1gcBUT---"
},
{
"id" : "r1ltUUpZbb"
}
]
}
{
"label" : "tom",
"id" : "SkF8UaW-W",
"children" : [
{
"id" : "S1gcBUT---"
},
{
"id" : "r1ltUUpZbb"
}
]
}
....
What I want to do is, replace id fields with the documents.
{
"id": "1",
"label" : "alex",
"children" : [
{
"id" : "rJqS8aW-W"
},
{
"id" : "SkF8UaW-W"
}
],
details: [
{
"label" : "felix",
"id" : "rJqS8aW-W",
"children" : [
{
"id" : "S1gcBUT---"
},
{
"id" : "r1ltUUpZbb"
}
]
},
{
"label" : "tom",
"id" : "SkF8UaW-W",
"children" : [
{
"id" : "S1gcBUT---"
},
{
"id" : "r1ltUUpZbb"
}
]
}
]
}
...
To be able to achieve this, I wrote;
db.collection.aggregate([
{$lookup: {from: "collection" , localField: "children.id", foreignField: "id", as: "details"}}
])
But it doesn't return as I expect. Can't we use $lookup with arrays? I mean I want to search based on a field in the array.
edit:
some modifications like,
db.collection.aggregate([
{$lookup: {from: "collection" , localField: "$children.id", foreignField: "id", as: "details"}}
])
or
db.collection.aggregate([
{$lookup: {from: "collection" , localField: "children.$.id", foreignField: "id", as: "details"}}
])
also throws error.
What should I do? flatting the children id field and than $lookup?

Related

How to collect string fields from lookup documents into an array field of root documents in MongoDb [duplicate]

For MongoDB, when using $lookup to query more than one collection, is it possible to get a values-only list for a field returned in the $lookup?
What I don't want is a list of the full object with all its key/values.
Data:
failover_tool:PRIMARY> db.foo.find().pretty()
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo"
}
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo"
}
failover_tool:PRIMARY> db.bar.find().pretty()
{
"_id" : ObjectId("5ce72e0c5267960532b8df06"),
"name" : "bar1",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e165267960532b8df07"),
"name" : "bar2",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e1d5267960532b8df08"),
"name" : "bar3",
"foo" : "foo2"
}
Desired Query Output
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : ["bar1", "bar2"]
},
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : ["bar3"]
}
Closest
This query seems like it's almost there, but it returns too much data in the bars field:
db.foo.aggregate({
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
}).pretty()
Just use .dot notation with the name field
db.foo.aggregate([
{ "$lookup": {
"from": "bar",
"localField": "name",
"foreignField": "foo",
"as": "bars"
}},
{ "$addFields": { "bars": "$bars.name" }}
])
MongoPlayground
Hope below query helps :
db.foo.aggregate([{
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
},
{$unwind : '$bars'},
{
$group : {
_id : {
_id : '$_id',
name : '$name',
desc : '$desc'
},
bars : { $push : '$bars.name'}
}
},
{
$project : {
_id : '$_id._id',
name : '$_id.name',
desc : '$_id.desc',
bars : '$bars'
}
}
]).pretty()
output :
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : [
"bar3"
]
}
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : [
"bar1",
"bar2"
]
}

How to display name with the id but with datas in 2 collections MongoDb?

I just want change a Id by thea name corresponding. But id is in a collection and name in other collection. "$lookup" Mongo doesn't work in my case...
The first collection "parameter" contains items with the "category_id":
{"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"data" : {
"capacity" : NumberInt(60),
"categories" : [
{
"category_id" : "5964961294ff4a37988e8f9b",
"nbMax" : NumberInt(1),
"nbRes" : NumberInt(0)
},
{
"category_id" : "596495c994ff4a37988e8f99",
"nbMax" : NumberInt(1),
"nbRes" : NumberInt(0)
},
],
},
"type" : "launcher",
"name" : "launcherp01",
"description" : "",
"_class" : "parameter"
}
....
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4847"),
"data" : {
"capacity" : NumberInt(60),
"categories" : [
{
"category_id" : "596495c994ff4a37988e8f99",
"nbMax" : NumberInt(1),
"nbRes" : NumberInt(0)
},
{
"category_id" : "8864961294ff4a37988e8f3b",
"nbMax" : NumberInt(1),
"nbRes" : NumberInt(0)
},
],
},
"type" : "launcher",
"name" : "launcherp01",
"description" : "",
"_class" : "parameter"
}
.....
The second Collection "reference" contains the description of categories with the _id (same as category_id in first collection) and the name:
{
"_id" : ObjectId("596495c994ff4a37988e8f99"),
"taskType" : "qc",
"type" : "category",
"name" : "**qcSupportNormal01**",
"_class" : "reference",
}
{
"_id" : ObjectId("5964961294ff4a37988e8f9b"),
"taskType" : "transcode",
"type" : "category",
"name" : "tsSupportNormal01",
"_class" : "reference",
}
I want something like that (item with categories names not id):
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"type" : "launcher",
"categories" : [
"qcSupportNormal01", //--->> name from reference collection
"tsSupportNormal01", //--->> name from reference collection
}
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4847"),
"type" : "launcher",
"categories" : [
"qcSupportNormal01", //--->> name from reference collection
"qptestNormal01", //--->> name from reference collection
...
My query:
db.parameters.aggregate([
///////////////////////item filter
{$match: {
type:{ $in: [ "launcher" ] } ,
}},
///////////////////// foreign field
{$lookup: {
from: "references",
localField: "categories",
foreignField: "_id",
as: "references"
}},
/////////////////// projection
{$project:
{_id:1,type:1,categories:"$data.categories.category_id"
}},
])
but the result is always with id not the name:
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"type" : "launcher",
"categories" : [
"5964961294ff4a37988e8f9b", //--->> id not name from reference collection !
"596495c994ff4a37988e8f99", //--->> id not name from reference collection !
...
How to have the category name not the id.
Very simple in Sql (joint with foreign key and reference table) but complex in Mongo query ...
Thanks for your help
je déteste le langage Mongo !
There are a couple of issues with your approach:
You are trying to call $lookup between an ObjectId and a string value.
For your categories field you are mapping it with the category_id from the data.categories whereas it should have come from references.name.
The field category_id is nested inside of an array and when you are calling the $lookup you are matching it with the whole array instead of the key field.
So, now the best approach would be to convert the field category_id to an ObjectId and then call the $lookup for the field(instead of modifying the actual field i have appended a new field named as cat_id).
Here is how i would do it:
db.parameter.aggregate([
{
$match: {
type: { $in: ["launcher"] },
}
},
{ $unwind: "$data.categories" },
{ $addFields: { "data.categories.cat_id": { $convert: { input: "$data.categories.category_id", to: "objectId" } } } },
{
$lookup: {
from: "references",
localField: "data.categories.cat_id",
foreignField: "_id",
as: "ref"
}
},
{
$project:
{
_id: 1, type: 1, categories: "$ref.name"
}
}
]);
Which will give you an output as:
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"type" : "launcher",
"categories" : [
"tsSupportNormal01"
]
},
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"type" : "launcher",
"categories" : [
"**qcSupportNormal01**"
]
},
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4847"),
"type" : "launcher",
"categories" : [
"**qcSupportNormal01**"
]
},
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4847"),
"type" : "launcher",
"categories" : [ ]
}

MongoDB aggregation $lookup pipeline convert from array of objects to flat array [duplicate]

For MongoDB, when using $lookup to query more than one collection, is it possible to get a values-only list for a field returned in the $lookup?
What I don't want is a list of the full object with all its key/values.
Data:
failover_tool:PRIMARY> db.foo.find().pretty()
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo"
}
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo"
}
failover_tool:PRIMARY> db.bar.find().pretty()
{
"_id" : ObjectId("5ce72e0c5267960532b8df06"),
"name" : "bar1",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e165267960532b8df07"),
"name" : "bar2",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e1d5267960532b8df08"),
"name" : "bar3",
"foo" : "foo2"
}
Desired Query Output
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : ["bar1", "bar2"]
},
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : ["bar3"]
}
Closest
This query seems like it's almost there, but it returns too much data in the bars field:
db.foo.aggregate({
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
}).pretty()
Just use .dot notation with the name field
db.foo.aggregate([
{ "$lookup": {
"from": "bar",
"localField": "name",
"foreignField": "foo",
"as": "bars"
}},
{ "$addFields": { "bars": "$bars.name" }}
])
MongoPlayground
Hope below query helps :
db.foo.aggregate([{
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
},
{$unwind : '$bars'},
{
$group : {
_id : {
_id : '$_id',
name : '$name',
desc : '$desc'
},
bars : { $push : '$bars.name'}
}
},
{
$project : {
_id : '$_id._id',
name : '$_id.name',
desc : '$_id.desc',
bars : '$bars'
}
}
]).pretty()
output :
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : [
"bar3"
]
}
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : [
"bar1",
"bar2"
]
}

Get values as array of elements after $lookup

For MongoDB, when using $lookup to query more than one collection, is it possible to get a values-only list for a field returned in the $lookup?
What I don't want is a list of the full object with all its key/values.
Data:
failover_tool:PRIMARY> db.foo.find().pretty()
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo"
}
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo"
}
failover_tool:PRIMARY> db.bar.find().pretty()
{
"_id" : ObjectId("5ce72e0c5267960532b8df06"),
"name" : "bar1",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e165267960532b8df07"),
"name" : "bar2",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e1d5267960532b8df08"),
"name" : "bar3",
"foo" : "foo2"
}
Desired Query Output
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : ["bar1", "bar2"]
},
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : ["bar3"]
}
Closest
This query seems like it's almost there, but it returns too much data in the bars field:
db.foo.aggregate({
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
}).pretty()
Just use .dot notation with the name field
db.foo.aggregate([
{ "$lookup": {
"from": "bar",
"localField": "name",
"foreignField": "foo",
"as": "bars"
}},
{ "$addFields": { "bars": "$bars.name" }}
])
MongoPlayground
Hope below query helps :
db.foo.aggregate([{
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
},
{$unwind : '$bars'},
{
$group : {
_id : {
_id : '$_id',
name : '$name',
desc : '$desc'
},
bars : { $push : '$bars.name'}
}
},
{
$project : {
_id : '$_id._id',
name : '$_id.name',
desc : '$_id.desc',
bars : '$bars'
}
}
]).pretty()
output :
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : [
"bar3"
]
}
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : [
"bar1",
"bar2"
]
}

Mongodb aggregation retrieving document from inside of document

I have problems with MongoDB's aggregation.
In my "Job" document, it has creatorParent(single value) and Children(array of mongodb object id). In the "User" document, user has children array with child details.
When user request for retrieving this document I want aggregate child details, if array contains id of child.
I wrote an aggregation with some help, It worked for creatorParent but whatever I've tried, it didn't worked for children.
db.getCollection('Jobs').aggregate([
{
$unwind: {
path : "$children"
}
},
{
$lookup: {
"from" : "Users",
"localField" : "creatorparent",
"foreignField" : "_id",
"as" : "creatorparent"
}
},
{
$lookup: {
"from" : "Users",
"localField" : "children",
"foreignField" : "children",
"as" : "children"
}
}
])
Users document:
{
"_id" : ObjectId("58daf84877733645eaa9b44f"),
"email" : "meto93#gmail.com",
"password" : "vpGl+Fjnef616cRgNbCkwaFDpSI=",
"passwordsalt" : "99397F4A9D3A499D96694547667E74595CE994D2E83345D6953EF866303E8B65",
"children" : [
{
"_id" : ObjectId("58daf84977733645eaa9b450"),
"name" : "Mert",
"age" : 5,
"additionalinformation" : "ilk cocuk",
"creationtime" : ISODate("2017-03-28T23:56:56.952Z"),
"userid" : ObjectId("58daf84877733645eaa9b44f"),
"gender" : null
},
{
"_id" : ObjectId("58daf84977733645eaa9b451"),
"name" : "Sencer",
"age" : 7,
"additionalinformation" : "ikinci cocuk",
"creationtime" : ISODate("2017-03-28T23:56:56.952Z"),
"userid" : ObjectId("58daf84877733645eaa9b44f"),
"gender" : null
}
]
}
Job
{
"_id" : ObjectId("58db0a2d77733645eaa9b453"),
"creationtime" : ISODate("2017-03-29T01:13:17.509Z"),
"startingtime" : ISODate("2017-04-03T13:00:00.000Z"),
"endingtime" : ISODate("2017-04-03T17:00:00.000Z"),
"children" : [
ObjectId("58daf84977733645eaa9b450"),
ObjectId("58daf84977733645eaa9b451")
],
"creatorparent" : ObjectId("58daf84877733645eaa9b44f"),
"applicants" : []
}
Try this:
db.jobs.aggregate(
[
{
$unwind: {
path : "$children",
}
},
{
$lookup: {
"from" : "users",
"localField" : "creatorparent",
"foreignField" : "_id",
"as" : "creatorparent"
}
},
{
$lookup: {
"from" : "users",
"localField" : "children",
"foreignField" : "children._id",
"as" : "children"
}
},
{
$addFields: {
children : {$arrayElemAt : ["$children",0]}
}
},
{
$addFields: {
"children":"$children.children"
}
},
{
$unwind: {
path : "$children",
}
},
{
$group: {
"_id": "$_id",
"name": { "$first": "$name" },
"jobstatus" : { "$first": "$jobstatus" },
"hourlyrate" : { "$first": "$hourlyrate" },
"creatorparent" : { "$first" : "$creatorparent" },
"children": { "$addToSet": "$children" }
}
},
]
);