Arangodb AQL Joining, merging, embedding nested three collections or more - arangodb

I have the following collections, based on the example Arangodb doc here but have added a third collection called region
Users
{
"name" : {
"first" : "John",
"last" : "Doe"
},
"city" : "cities/2241300989",
"_id" : "users/2290649597",
"_rev" : "2290649597",
"_key" : "2290649597"
}
Cities
{
"population" : 1000,
"name" : "Metropolis",
"region" : "regions/2282300990",
"_id" : "cities/2241300989",
"_rev" : "2241300989",
"_key" : "2241300989"
}
Regions
{
"name" : "SomeRegion1",
"_id" : "regions/2282300990",
"_rev" : "2282300990",
"_key" : "2282300990"
}
I want to have a target result like this
[
{
"user" : {
"name" : {
"first" : "John",
"last" : "Doe"
},
"_id" : "users/2290649597",
"_rev" : "2290649597",
"_key" : "2290649597"
},
"city" : {
"population" : 1000,
"name" : "Metropolis",
"_id" : "cities/2241300989",
"_rev" : "2241300989",
"_key" : "2241300989",
"region" : {
"name" : "SomeRegion1",
"_id" : "regions/2282300990",
"_rev" : "2282300990",
"_key" : "2282300990"
}
}
}
]
The example in the Arangodb doc here only has queries for two collections
FOR u IN users
FOR c IN cities
FILTER u.city == c._id RETURN merge(u, {city: c})
# However I want to have more than two collections e.g.
FOR u IN users
FOR c IN cities
For r IN regions
FILTER u.city == c._id and c.region == r._id RETURN merge(????????)
How would you get the result with three collections joined as above? What happens if I want a forth nested one?

When you store a document _id that references another collection, then you can leverage the DOCUMENT AQL command.
So your AQL query becomes a bit simpler, like this:
FOR u IN users
LET city = DOCUMENT(u.city)
LET city_with_region = MERGE(city, { region: DOCUMENT(city.region})
RETURN MERGE(u, { city: city_with_region})
This query could be collapsed even more, but I left it like this so it's more self documenting.
What is cool about DOCUMENT is you can return only a single attribute of a document, such as LET region_name = DOCUMENT(city.region).name.
I've also found that in most cases it's more performant that doing a subquery to locate the document.

Probably something like this:
FOR u IN users
FOR c IN cities
For r IN regions
FILTER u.city == c._id AND c.region == r._id
RETURN { user: u, city: MERGE(c, {region: r } }
Is there a particular reason why you store ids instead of keys to refer to cities and regions? The _id is just a virtual field that consists of the _key prefixed by the collection name (plus a slash). So this would work just as well (I intentionally omit the internal _id and _rev fields):
Users
{
"name" : {
"first" : "John",
"last" : "Doe"
},
"city" : "2241300989",
"_key" : "2290649597"
}
Cities
{
"population" : 1000,
"name" : "Metropolis",
"region" : "2282300990",
"_key" : "2241300989"
}
Regions
{
"name" : "SomeRegion1",
"_key" : "2282300990"
}
FOR u IN users
FOR c IN cities
For r IN regions
FILTER u.city == c._key AND c.region == r._key
RETURN { user: u, city: MERGE(c, {region: r } }

Related

how to get the another collection data whose id is stored in array

I am having a collection like this whose users ids are stored inside the array,I need to query the collection A to get collection B whose "_id" (only "_id") is stored in array type , how to get in mongodb using aggregate ?
collection A :
{
"_id" : ObjectId("5ccfc2d176013e48a4ec0eed"),
"position" : ObjectId("5c73bcd0697b545c329a4bd4"),
"users" : [
"5bbf3cc7381e7a6530872089"
],
"inCase" : [],
"completed" : false,
}
am having second collection as
Collection B
{
"_id" : ObjectId("5b517a2bebb3b14b4cd78ca9"),
"firstName" : "Katie",
"lastName" : "Carter",
"languages" : [
"English",
"",
""
],
}
My code
{$lookup:{from:'user',localField:'users',foreignField:'_id',as:'users'}},
{$unwind:'$users'},
let me know how to resolve it?

$merge, $match and $update in one aggregate query

I have data in a collection ex:"jobs". I am trying to copy specific data from "jobs" after every 2 hours to a new collection (which may not exist initially) and also add a new key to the copied data.
I have been trying with this query to copy the data:
db.getCollection("jobs").aggregate([{ $match: { "job_name": "UploadFile", "created_datetime" : {"$gte":"2021-08-18 12:00:00"} } },{"$merge":{into: {coll : "reports"}}}])
But after this, the count in "reports" collection is 0. Also, how can I update the documents (with an extract key "report_name") without using an extra updateMany() query?
The data in jobs collection is as shown:
{
"_id" : ObjectId("60fa8e8283dc22799134dc6f"),
"job_id" : "408a5654-9a89-4c15-82b4-b0dc894b19d7",
"job_name" : "UploadFile",
"data" : {
"path" : "share://LOCALNAS/Screenshot from 2021-07-23 10-34-34.png",
"file_name" : "Screenshot from 2021-07-23 10-34-34.png",
"parent_path" : "share://LOCALNAS",
"size" : 97710,
"md5sum" : "",
"file_uid" : "c4411f10-a745-48d0-a55d-164707b7d6c2",
"version_id" : "c3dfd31a-80ba-4de0-9115-2d9b778bcf02",
"session_id" : "c4411f10-a745-48d0-a55d-164707b7d6c2",
"resource_name" : "Screenshot from 2021-07-23 10-34-34.png",
"metadata" : {
"metadata" : {
"description" : "",
"tag_ids" : [ ]
},
"category_id" : "60eed9ea33c690a0dfc89b41",
"custom_metadata" : [ ]
},
"upload_token" : "upload_token_c5043927484e",
"upload_url" : "/mnt/share_LOCALNAS",
"vfs_action_handler_id" : "91be4282a9ad5067642cdadb75278230",
"element_type" : "file"
},
"user_id" : "60f6c507d4ba6ee28aee5723",
"node_id" : "syeda",
"state" : "COMPLETED",
"priority" : 2,
"resource_name" : "Screenshot from 2021-07-23 10-34-34.png",
"group_id" : "upload_group_0babf8b7ce0b",
"status_info" : {
"progress" : 100,
"status_msg" : "Upload Completed."
},
"error_code" : "",
"error_message" : "",
"created_datetime" : ISODate("2021-07-23T15:10:18.506Z"),
"modified_datetime" : ISODate("2021-07-23T15:10:18.506Z"),
"schema_version" : "1.0.0",
}
Your $match stage contains a condition which takes created_datetime as string while in your sample data it is an ISODate. Such condtion won't return any document, try:
{
$match: {
"job_name": "UploadFile",
"created_datetime": {
"$gte": ISODate("2021-07-01T12:00:00.000Z")
}
}
}
Mongo Playground

finding the parent document id based on the sub document _id of array field

Hyy , I have a collection where comments related to the blog are stored in multiple document as shown below.
[
{
"_id" : ObjectId("565f0f5d77f0c7bd11bbadd8"),
"blog_id" : ObjectId("56587befdb7224110f007233"),
"comments" : [
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "pradip is bhole baba",
"_id" : ObjectId("565f0f5d77f0c7bd11bbadd9"),
"dt" : ISODate("2015-12-02T15:33:49.578Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "honkog pokhara... he he ha ha",
"_id" : ObjectId("565f1034fd07cbfc1129db0b"),
"dt" : ISODate("2015-12-02T15:37:24.581Z")
}
],
"record_count" : 2,
"__v" : 0
}
{
"_id" : ObjectId("565efa37635f09900d21a339"),
"blog_id" : ObjectId("56587befdb7224110f007233"),
"comments" : [
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "wat a nice car wow",
"_id" : ObjectId("565efa37635f09900d21a33a"),
"dt" : ISODate("2015-12-02T14:03:35.289Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "love is life budikhola ma dives",
"_id" : ObjectId("565efa76635f09900d21a33b"),
"dt" : ISODate("2015-12-02T14:04:38.661Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "bholi ajaya ko bihe",
"_id" : ObjectId("565efaa0635f09900d21a33c"),
"dt" : ISODate("2015-12-02T14:05:20.847Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "manish is nice",
"_id" : ObjectId("565efb17635f09900d21a33d"),
"dt" : ISODate("2015-12-02T14:07:19.704Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "niroj is cool",
"_id" : ObjectId("565efd53c22dddc80e8f461c"),
"dt" : ISODate("2015-12-02T14:16:51.730Z")
},
{
"user_id" : ObjectId("562fa014888806820e21e0df"),
"user_full_name" : "Niroj Paudel",
"comment" : "ramesh is cool",
"_id" : ObjectId("565f0d376d82e24c11f6c0d1"),
"dt" : ISODate("2015-12-02T15:24:39.010Z")
}
],
"record_count" : 6,
"__v" : 0
}
]
Suppose user wants to update his comment; for this I would have the comments _id now my problem is that how can I detect in which document the comment exist based of the comment _id value of comments array field.
suppose I have a comment "_id" : "565f0f5d77f0c7bd11bbadd9" (first element of first document)
then the result should give the parent document _id:"565f0f5d77f0c7bd11bbadd8" (first document id)
How can I do this..
Thank you in advance
if possible, then please update your schema.
Suppose you have collection of Blog. Then your code will be :
Blog.find({'comments._id' : '565f0f5d77f0c7bd11bbadd9'}).exec(function(err,blog){
if(!err && blog){
console.log("Blog id :"+blog._id);
}
else{
console.log("Dont get your blog");
}
});
if your comments are directly stored on the blog document you could go with an aggregate method to collect the comment across all documents. note that this seems to work when you don't have any object references to be populated.
asuming all documents are based on a blog Schema and that you wish to recieve the id of the comment:
Blog.aggregate(
[{'$match':{'comments':{'$elemMatch:{'_id':'565f0f5d77f0c7bd11bbadd9'}}}},
{'$project':{comments:'$_id', user_id:1}},
{'$unwind':'$comments'}
{'$group':{_id:'$comments'}}
]).exec(function(err, results){
if(results){
console.log(results);
}
});
I hope this is somewhat what you're looking for, you might find the following read usefull
elementMatch and aggregation from the mongoDB docs.
cheers!
The site recommended this old question to me as being Related to another I was looking at. Looks like a sufficient answer wasn't ever given, so I'll provide it for any future readers.
The requested behavior here is very straightforward to achieve with a basic find() query:
db.collection.find(
{ "comments._id": ObjectId("565f0f5d77f0c7bd11bbadd9") },
{ _id: 1 }
)
Here we are filtering the documents based on the values of the _id fields embedded in the comments array. Then for the matching document(s) we are applying a projection to just retrieve the _id field of the "parent document" (e.g. the document that was matched). If the _ids for the comments are unique then there will only ever be a maximum of a single matching document. Sample playground demonstration is here.
A more complicated aggregation would have only been necessary here if the intent was to always provide the _id value of the first document associated with a given blog_id but that does not appear to be the case here.

Find documents with sub-documents matching both of two (or more) properties

In Node with Mongoose I want to find an object in the collection Content. It has a list of sub-documents called users which has the properties stream, user and added. I do this to get all documents with a certain user's _id property in there users.user field.
Content.find( { 'users.user': user._id } ).sort( { 'users.added': -1 } )
This seems to work (although I'm unsure if .sort is really working here. However, I want to match two fields, like this:
Content.find( { 'users.user': user._id, 'users.stream': stream } } ).sort( { 'users.added': -1 } )
That does not seem to work. What is the right way to do this?
Here is a sample document
{
"_id" : ObjectId("551c6b37859e51fb9e9fde83"),
"url" : "https://www.youtube.com/watch?v=f9v_XN7Wxh8",
"title" : "Playing Games in 360°",
"date" : "2015-03-10T00:19:53.000Z",
"author" : "Econael",
"description" : "Blinky is a proof of concept of enhanced peripheral vision in video games, showcasing different kinds of lens projections in Quake (a mod of Fisheye Quake, using the TyrQuake engine).\n\nDemo and additional info here:\nhttps://github.com/shaunlebron/blinky\n\nThanks to #shaunlebron for making this very interesting proof of concept!\n\nSubscribe: http://www.youtube.com/subscription_center?add_user=econaelgaming\nTwitter: https://twitter.com/EconaelGaming",
"duration" : 442,
"likes" : 516,
"dislikes" : 13,
"views" : 65568,
"users" : [
{
"user" : "54f6688c55407c0300b883f2",
"added" : 1427925815190,
"_id" : ObjectId("551c6b37859e51fb9e9fde84"),
"tags" : []
}
],
"images" : [
{
"hash" : "1ab544648d7dff6e15826cda7a170ddb",
"thumb" : "...",
"orig" : "..."
}
],
"tags" : [],
"__v" : 0
}
Use $elemMatch operator to specify multiple criteria on an array of embedded documents:
Content.find({"users": {$elemMatch: {"user": user.id, "stream": stream}}});

Upsert embedded object in mongoDB

Given this Person collection:
{
"_id" : ObjectId("4f8e95a718bcv9c74da1e6511a"),
"name" : "John",
"hobbies" : [{
"id" : 001,
"name" : "reading",
"location" : "home"
},{
"id" : 002,
"name" : "sport",
"location" : "outside"
}]
}
and these new/edited Hobby objects:
{
"name" : "walking",
"location" : "outside"
}
and
{
"id" : 001,
"name" : "reading",
"location" : "outside"
}
If I know the Person that I want to manage, what is be the best way to upsert embedded objects?
Currently my approach is to find the Person object, make the required modifications to it in my code, and then save it back to the DB. This works. But I'd like to simplify and reduce the number of round trips to the database.

Resources