{
"_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
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
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?
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!!!"
}
],
{
"_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..
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.