Nested lookup in mongodb - mongodb

{
"_id": "445454",
"students": ["7894556", "5454454"]
}
This is my actual data. After first lookup I got a result like:
{
"_id": "445454",
"students": [{
"name": "Jose",
"parent": "45566622"
},{
"name": "Mathew",
"parent": "7889665"
}]
}
but actual answer I required is something like this
{
"_id": "445454",
"students": [{
"name": "Jose",
"parent": {
"_id": "45566622",
"name": "Cristy"
}
}, {
"name": "Mathew",
"parent": {
"_id": "7889665",
"name": "Abraham"
}
}]
}
somebody please help me. I not expert in mongodb.

Related

How to add field in all nested documents in mongo

I have a document with a tree structure:
{
"_id": "62e1f19f094a5696fd18f4e9",
"parent": null,
"children": [
{
"_id": "44e1f19f094a5696fd18f4o7",
"parent": "62e1f19f094a5696fd18f4e9",
"children": [
{
"_id": "62e1f19f094a5696fd18f4e9",
"parent": "44e1f19f094a5696fd18f4o7",
"children": []
}
]
}
]
}
I want to add a new field "id" (without the underscore) which refers to "_id" to each document even if it is a child or parent
I tried to do something like this:
$addFields: {id: $_id, children.id: $children._id} but in doesn't work
so, the final result I want to get
{
"_id": "62e1f19f094a5696fd18f4e9",
"id": "62e1f19f094a5696fd18f4e9",
"parent": null,
"children": [
{
"_id": "44e1f19f094a5696fd18f4o7",
"id": "44e1f19f094a5696fd18f4o7",
"parent": "62e1f19f094a5696fd18f4e9",
"children": [
{
"_id": "62e1f19f094a5696fd18f4e9",
"id": "62e1f19f094a5696fd18f4e9",
"parent": "44e1f19f094a5696fd18f4o7",
"children": []
}
]
}
]
}
Based on a question by #rickhg12hs:
It can be done, but I agree with #turivishal that if you are doing it, it is reasonable to store it once (a minor change to the query):
db.collection.aggregate([
{
$replaceRoot: {
newRoot: {
$function: {
body: "function drill(r) {r.id = r._id; if (r.children.length > 0) { for (let elem of r.children) { drill(elem)}} return r};",
args: [
"$$ROOT"
],
lang: "js"
}
}
}
}
])
See how it works on the playground example
For storing on the db, instead of aggregate use an update with pipeline, like this

MongoDB lookup with multiple nested levels

In my application, I have a section of comments and replies under some documents.
Here's how my database schema looks like
db.updates.insertOne({
"_id": "62347813d28412ffd82b551d",
"documentID": "17987e64-f848-40f3-817e-98adfd9f4ecd",
"stream": [
{
"id": "623478134c449b218b68f636",
"type": "comment",
"text": "Hey #john, we got a problem",
"authorID": "843df3dbbdfc62ba2d902326",
"taggedUsers": [
"623209d2ab26cfdbbd3fd348"
],
"replies": [
{
"id": "623478284c449b218b68f637",
"type": "reply",
"text": "Not sure, let's involve #jim here",
"authorID": "623209d2ab26cfdbbd3fd348",
"taggedUsers": [
"26cfdbbd3fd349623209d2ab"
]
}
]
}
]
})
db.users.insertMany([
{
"_id": "843df3dbbdfc62ba2d902326",
"name": "Manager"
},
{
"_id": "623209d2ab26cfdbbd3fd348",
"name": "John"
},
{
"_id": "26cfdbbd3fd349623209d2ab",
"name": "Jim"
},
])
I want to join those two collections, and replace user ids with complete user information on all levels. So the final JSON should look like this
{
"_id": "62347813d28412ffd82b551d",
"documentID": "17987e64-f848-40f3-817e-98adfd9f4ecd",
"stream": [
{
"id": "623478134c449b218b68f636",
"type": "comment",
"text": "Hey #john, we got a problem",
"author": {
"_id": "843df3dbbdfc62ba2d902326",
"name": "Manager"
},
"taggedUsers": [
{
"_id": "623209d2ab26cfdbbd3fd348",
"name": "John"
}
],
"replies": [
{
"id": "623478284c449b218b68f637",
"type": "reply",
"text": "Not sure, let's involve #jim here",
"author": {
"_id": "623209d2ab26cfdbbd3fd348",
"name": "John"
},
"taggedUsers": [
{
"_id": "26cfdbbd3fd349623209d2ab",
"name": "Jim"
}
]
}
]
}
]
}
I know how to do the $lookup on the top-level fields, including pipelines, but how can I do with the nested ones?

Populate one path of an object nested inside array for specific fileds

My Posts Schema has a "comments" array path, for each "comment", "user" is objectId to User Modal. How could I populate only "name", "_id", "thumbnailURI" for the user.
what the posts db looks like:
[
...
{
"_id": "5ce5b41222fa4937f8a495e5",
"owner": "5ce5b41123456789f8a495e5",
"uri": "uri.jpg",
"comments": [
{
"date": "2019-05-23T23:24:47.554Z",
"_id": "5ce72bbf88781b35fca696ce",
"user": "5cdda3a4f5a8a077a9352f38",
"content": "cute!!!"
},
{
"date": "2019-05-23T23:28:52.941Z",
"_id": "5ce72cb46fba6f1bece267db",
"user": "5cdda3a4f5a8a077a9352f38",
"content": "cute!!!"
}
],
"createAt": "2019-05-22T20:41:54.290Z",
"__v": 0
},
...
]
I want the "comments" looks like this:
"comments": [
{
"date": "2019-05-23T23:24:47.554Z",
"_id": "5ce72bbf88781b35fca696ce",
"user": {
"name": "name",
"_id": "5ce72cb46fb5ce72cb46fb"
"thumbnailURI": "thumbnailURI.jpg"
},
"content": "cute!!!"
},
{
"date": "2019-05-23T23:28:52.941Z",
"_id": "5ce72cb46fba6f1bece267db",
"user": {
"name": "name",
"_id": "5ce72cb46fb5ce72cb46fb"
"thumbnailURI": "thumbnailURI.jpg"
},
"content": "cute!!!"
}
],
Tried
posts
.getByOwners(owners)
.populate('owner', 'username thumbnail _id')
.populate({
path: "comments",
populate: {
path: "user",
model: "user",
}
});
get empty "comments" array
Thank you!
Thanks for the advises.
I have a "user" model with some paths
There is no "comments" model. "comments" is an array embedded in "post" model.
The query looks like this:
posts
.findById(id)
.populate('owner', 'username thumbnail _id')
.populate("comments.user", 'username thumbnail _id')
This is the final result I want:
"comments": [
{
"date": "2019-05-23T23:24:47.554Z",
"_id": "5ce72bbf88781b35fca696ce",
"user": {
"thumbnail": "pic1.jpg",
"_id": "5cdda3a4f5a8a077a9352f38",
"username": "a"
},
"content": "cute!!!"
},
{
"date": "2019-05-23T23:28:52.941Z",
"_id": "5ce72cb46fba6f1bece267db",
"user": {
"thumbnail": "pic2.jpg",
"_id": "5cdda3a4f5a8a077a9352f38",
"username": "a"
},
"content": "cute!!!"
}
],

Find and Update Inner Array - MongoDB

{
"_id": {
"$oid": "5a99553c1b4a1b0922039e73"
},
"date_added": {
"$date": "2018-03-02T13:42:36.684Z"
},
"title": "Black Panther",
"__v": 14,
"alls": [
{
"name": "Mbezi",
"geocoordinates": "-6.8140361,39.2775983",
"region": "Dar es salaam",
"times": "",
"_id": {
"$oid": "5a9c74885980731a35a013b2"
}
},
{
"name": "DFM",
"geocoordinates": "-6.7726935,39.2196418",
"region": "Dar es salaam",
"times": "",
"_id": {
"$oid": "5a9c7f61bb57291a81d8309e"
}
}
]
}
How can i find alls name equals to "Mbezi" and update times to a certain value? Any links that can help me will be appreciated..

Get the first document using $in with mongodb

how can get the first element using in in mongo ?
if i've a list like ['car', 'house', 'cat', dog'], and a collection which contains many documents these element, i'd like to find the first document which contain cat, and first which contains dog etc.
I've tried to use limit() but in fact it gives me only one document, which can be either car, or dog or cat etc.
is there a way to combine a limit with $in ?
Thanks
EDIT:
example of data i've:
{
"_id": {
"$oid": "51d53ace9e674607e837d62d"
},
"sensors": [{
"name": "os-hostname",
"value": "yahourt"
}, {
"name": "os-domain-name",
"value": ""
}, {
"name": "os-platform",
"value": "Win32NT"
}, {
"name": "os-fullname",
"value": "Microsoft Windows XP Professional"
}, {
"name": "os-version",
"value": "5.1.2600.131072"
}],
"type": "os",
"serial": "2_os_os-hostname_yahourt"
} {
"_id": {
"$oid": "51d53ace9e674607e837d62e"
},
"sensors": [{
"name": "cpu-id",
"value": "_Total"
}, {
"name": "cpu-usage",
"value": 37.2257042
}],
"type": "cpu",
"serial": "2_cpu_cpu-id_total"
} {
"_id": {
"$oid": "51d53ace9e674607e837d62f"
},
"sensors": [{
"name": "cpu-id",
"value": "0"
}, {
"name": "cpu-usage",
"value": 48.90282
}],
"type": "cpu",
"serial": "2_cpu_cpu-id_0"
} {
"_id": {
"$oid": "51d53ace9e674607e837d630"
},
"sensors": [{
"name": "cpu-id",
"value": "1"
}, {
"name": "cpu-usage",
"value": 25.54859
}],
"type": "cpu",
"serial": "2_cpu_cpu-id_1"
} {
"_id": {
"$oid": "51d53ace9e674607e837d631"
},
"sensors": [{
"name": "volume-name",
"value": "C:"
}, {
"name": "volume-label",
"value": ""
}, {
"name": "volume-total-size",
"value": "52427898880"
}, {
"name": "volume-total-free-space",
"value": "20305170432"
}, {
"name": "volume-percent-free-space",
"value": "38"
}, {
"name": "volume-reads-per-second",
"value": 0.0
}, {
"name": "volume-writes-per-second",
"value": 9.324152
}, {
"name": "volume-read-bytes-per-second",
"value": 0.0
}, {
"name": "volume-write-bytes-per-second",
"value": 194141.6
}, {
"name": "volume-queue-length",
"value": 0.0
}],
"type": "disk",
"serial": "2_disk_volume-name_c"
}
You cannot add a limit to $in but you could cheat by using the aggregation framework:
db.collection.aggregate([
{$match:{serial:{$in:[list_of_serials]}}},
{$sort:{_id:-1}},
{$group:{_id:'$serial',type:{$first:'$type'},sensors:{$first:'$sensors'},id:{$first:'$_id'}}}
]);
Would get a list of all first found of each type.
Edit
The update will get the last inserted according to the _id.