MongoDB finding all subdocuments where subDocument _ids like "string" - mongodb

Sample document structure is like:
{
"_id" : "https://docs.mongodb.org/manual",
"collection" : {
"_id" : "collection",
"urls" : [
"https://docs.mongodb.org/manual/c1",
"https://docs.mongodb.org/manual/c2"
]
},
"collectionNew" : {
"_id" : "collection1",
"urls" : [
"https://docs.mongodb.org/manual/c1New",
"https://docs.mongodb.org/manual/c2New"
]
},
"log" : {
"_id" : "log",
"urls" : [
"https://docs.mongodb.org/manual/l1",
"https://docs.mongodb.org/manual/l2"
]
}
}
I have multiple such documents in my collection.
After finding document by
db.AutoSearch.find({"_id": "https://docs.mongodb.org/manual"})
i want to search all subdocuments under this with name like "collection"
SOLUTION
I changed my document structure to:
{
"_id" : "https://docs.mongodb.org/manual",
"contents" : [
{
"_id" : "connect",
"urls" : [
"https://docs.mongodb.org/manual/search/?query=connect"
]
},
{
"_id" : "connection",
"urls" : [
"https://docs.mongodb.org/manual/search/?query=connection",
"https://docs.mongodb.org/manual/search/?query=connection%20pymongo"
]
}
{
"_id" : "list",
"urls" : [
"https://docs.mongodb.org/manual/search/?query=listfiles",
"https://docs.mongodb.org/manual/search/?query=listdatabases",
"https://docs.mongodb.org/manual/search/?query=listcommands"
]
},
{
"_id" : "log",
"urls" : [
"http://docs.mongodb.org/manual/tutorial/rotate-log-files/",
"http://docs.mongodb.org/manual/reference/log-messages/"
]
},
{
"_id" : "index",
"urls" : [
"https://docs.mongodb.org/manual/search/?query=index-related%20commands"
]
}
]}
Then by using mongoDB aggregate query
db.AutoSearch.aggregate([{$match:{ "_id": "https://docs.mongodb.org/manual"}},
{$unwind: '$contents'},
{$match:{"contents._id":/connect/}}])
I got the desired output.

Related

Sort query for dynamic array in Mongo DB

I have a collection in MongoDB like below format. Now i want to know how to apply sorting. Please find example of collection below,
{
"_id" : ObjectId("5e5e140f113a6c3970eef3bb"),
"FormId" : "5cd3a0a0cb20953208fcb549",
"FieldsDatas" : [
{
"FieldId" : "4fbcef5b-d60a-4908-a037-5ff085b70709",
"Value" : [
"202003031"
]
},
{
"FieldId" : "708e1baf-fcd0-45fa-b1de-27f34391c35c",
"Value" : [
"202003031"
]
},
{
"FieldId" : "0b563a80-2b0a-4803-ad7f-652a381e134c",
"Value" : [
"New Source",
"Endpoint"
]
},
{
"FieldId" : "15355b82-4fae-4c09-acb4-13f95e8c2d4e",
"Value" : [
"2020-03-03 13:51:17"
]
},
{
"FieldId" : "1e32a283-34a9-4a7b-b851-3e5ac7f93d2c",
"Value" : [
"tets"
]
}
]
}
{
"_id" : ObjectId("5e5e1c89113a6c3970eef3bc"),
"FormId" : "5cd3a0a0cb20953208fcb549"
"FieldsDatas" : [
{
"FieldId" : "708e1baf-fcd0-45fa-b1de-27f34391c35c",
"Value" : [
"202003032"
]
},
{
"FieldId" : "0eca0881-a69b-4db3-b8b1-d74b0a16d4ef",
"Value" : [
"20200303_2#mail.com"
]
},
{
"FieldId" : "2da67714-aaf3-433d-9a86-1b48c75470ec",
"Value" : [
"mani lj"
]
},
{
"FieldId" : "a0b26aac-cad0-4c5e-83b4-9a01ac4ce97a",
"Value" : []
},
{
"FieldId" : "15355b82-4fae-4c09-acb4-13f95e8c2d4e",
"Value" : [
"2020-03-03 14:29:23"
]
}
]
}
For above collection i have date inside the array of objects called FieldsDatas where "FieldId": "15355b82-4fae-4c09-acb4-13f95e8c2d4e" in that same "Value" array has datetime. I want to sort the result based in this datetime.
I have a filter query. How to add sort query for above scenario?
db.getCollection('Collection').find({
"$and":[
{
FieldsDatas: {
$elemMatch:{
FieldId:'955c9843-1535-4df8-a1c4-09430ac9f6ba',
Value: { $ne: ["Contact"] }
}
}
}
]
})
.limit(5)
.skip(30);
Anyone please help me to add sorting for this query like above datetime field.
Any possibilities to achieve this by Stored procedure or functions. Please let me know.
Thanks in advance,
Mani

Create an unique list of multiple arrays inside a subdocument.

I would like to create an unique list of array values inside a subdocument.
Document:
{
"_id" : ObjectId("5aee0e3c059638093b69c8b3"),
"firstname" : "John",
"lastname" : "Doe",
"websites" : [
{
"_id" : ObjectId("123"),
"key" : "website2",
"url" : "www.xxx.com",
"tags" : [
"php",
"python",
"java"
]
},
{
"_id" : ObjectId("456"),
"key" : "website2",
"url" : "www.yyy.com",
"tags" : [
"java",
"php"
]
},
{
"_id" : ObjectId("789"),
"key" : "website3",
"url" : "www.zzz.com",
"tags" : [
"java",
"html",
"css"
]
}
]
}
Expected output:
{
"_id" : ObjectId("5aee0e3c059638093b69c8b3"),
"firstname" : "John",
"lastname" : "Doe",
"unique_tags": [
"java",
"php",
"python",
"html",
"css",
],
"websites" : [
{
"_id" : ObjectId("123"),
"key" : "website2",
"url" : "www.xxx.com",
"tags" : [
"php",
"python",
"java"
]
},
{
"_id" : ObjectId("456"),
"key" : "website2",
"url" : "www.yyy.com",
"tags" : [
"java",
"php"
]
},
{
"_id" : ObjectId("789"),
"key" : "website3",
"url" : "www.zzz.com",
"tags" : [
"java",
"html",
"css"
]
}
]
}
It looks like Mongo has a distinct functionality, but this does not work inside an aggregate query (right?!).
Also tried to unwind on websites.tags and use the addToSet functionality but it also hasn't the right output.
Any ideas?
You can try below aggregation:
db.col.aggregate([
{
$addFields: {
unique_tags: {
$reduce: {
input: {
$concatArrays: {
$map: {
input: "$websites",
as: "website",
in: "$$website.tags"
}
}
},
initialValue: [],
in: { $setUnion : ["$$value", "$$this"]}
}
}
}
}
])
To flatten an array of arrays (websites -> tags) you can use $map with $concatArrays. Then you'll get an array of all tags from all websites. To get only unique values you can use $reduce with $setUnion (which drops duplicates).

How to compare array Field with Array input value in $filter mongodb

I willing to apply $filter in this collection to get only "Applied Mathematics" result only in array. I am providing input in form of array like this ["Applied Mathematics"] to below collection.
{
"_id" : ObjectId("58a95d81eead32e82932b535"),
"univisorEducation" : [
{
"educationLevel" : "BACHELOR",
"courseType" : "UNDERGRADUATE",
"year" : 2016,
"college" : ObjectId("58a936add48f2b502858a70d"),
"_id" : ObjectId("58a95eb2eead32e82932b541"),
"course" : [
"Anthropology",
"Biomedical Engineering",
"Applied Mathematics"
]
}
]
}
{
"_id" : ObjectId("58a9643deead32e82932b54b"),
"univisorEducation" : [
{
"educationLevel" : "DOCTORATE",
"courseType" : "GRADUATE",
"year" : 2020,
"college" : ObjectId("58a936afd48f2b502858b5e2"),
"_id" : ObjectId("58a96495eead32e82932b550"),
"course" : [
"Applied Mathematics",
"Applied Physics"
]
},
{
"educationLevel" : "MASTER",
"courseType" : "GRADUATE",
"year" : 2020,
"college" : ObjectId("58a936afd48f2b502858b9f7"),
"_id" : ObjectId("58a96495eead32e82932b54f"),
"course" : [
"Applied Mathematics"
]
}
]
}
For this purpose i am using a $filter in $project, below is my $filter code
$filter: {
input: "$univisorEducation",
as: "univisorEducation",
cond: {
$setIsSubset: ["$$univisorEducation.course", courses]
}
}
Issue is that i am only getting this result
{ "_id" : ObjectId("58a95d81eead32e82932b535"), "univisorEducation" : [ ] }
{
"_id" : ObjectId("58a9643deead32e82932b54b"),
"univisorEducation" : [
{
"educationLevel" : "MASTER",
"courseType" : "GRADUATE",
"year" : 2020,
"college" : ObjectId("58a936afd48f2b502858b9f7"),
"_id" : ObjectId("58a96495eead32e82932b54f"),
"course" : [
"Applied Mathematics"
]
}
]
}
The collection with "_id" : ObjectId("58a95d81eead32e82932b535") should have result with Applied Mathematics.
Change your $filter aggregation to below.
Compares courses array to univisorEducation.course and returns true there is match univisorEducation.course or false otherwise.
$filter: {
input: "$univisorEducation",
as: "univisorEducation",
cond: {
$ne:[{$setIntersection: [courses, "$$univisorEducation.course" ]}, []]
}
}

Mongoose aggregation improvement

Given this dataset and this mongodb, how to properly convert this aggregation into Mongoose?
I have included, the code using mongoose, which works but I want to know if this is the right way of doing it and that if this aggregation can be improved?
Thanks.
db.cars.aggregate(
//De-normalized the nested array of accounts
{"$unwind": "$accounts"},
//De-normalized the nested array of cars
{"$unwind": "$accounts.cars"},
//match carId to 3C
{"$match": {"accounts.cars.carId" : "3C"}},
//Project the accounts.cars object only
{"$project" : {"accounts.cars" : 1}}
).pretty();
The Mongoose version that I'm trying to improve:
Car.aggregate()
.unwind('accounts')
.unwind('accounts.cars')
.match({'accounts.cars.carId' : "3C"})
.project({"accounts.cars": 1, _id: 0})
.exec(function (err, carsObj) {});
and the dataset (cars):
{
"_id" : ObjectId("56223329b64f07a40ef1c15c"),
"username" : "john",
"email" : "john#john.com",
"accounts" : [
{
"_id" : ObjectId("56322329b61f07a40ef1c15d"),
"cars" : [
{
"carId" : "6A",
"_id" : ObjectId("56323329b64f07a40ef1c15e")
},
{
"carId" : "6B",
"_id" : ObjectId("56323329b64f07a40ef1c15e")
}
]
}
]
},
{
"_id" : ObjectId("56223125b64f07a40ef1c15c"),
"username" : "paul",
"email" : "paul#paul.com",
"accounts" : [
{
"_id" : ObjectId("5154729b61f07a40ef1c15d"),
"cars" : [
{
"carId" : "5B",
"_id" : ObjectId("56323329854f07a40ef1c15e")
}
]
},
{
"_id" : ObjectId("56322117b61f07a40ef1c15d"),
"cars" : [
{
"carId" : "6G",
"_id" : ObjectId("51212929b64f07a40ef1c15e")
},
{
"carId" : "3C",
"_id" : ObjectId("51273329b64f07a40ef1c15e")
},
{
"carId" : "4N",
"_id" : ObjectId("51241279b64f07a40ef1c15e")
}
]
}
]
}
What the aggregation returns is:
[
{ accounts:
{ cars:
{
"carId" : "3C",
"_id" : ObjectId("51273329b64f07a40ef1c15e")
}
}
}
]

mongodb how to retrieve all the value in fields type array?

Is there a way to retrieve all the values
of a fields type array
ie
{ "slug" : "my-post", "status" : "publish", "published" : ISODate("2014-01-26T18:28:11Z"), "title" : "my post", "body" : "my body post", "_id" : ObjectId("52e553c937fb8bf218b8c624"), "tags" : [ "js", "php", "scala" ], "created" : ISODate("2014-01-26T18:28:25.298Z"), "author" : "whisher", "__v" : 0 }
{ "slug" : "my-post-2", "status" : "publish", "published" : ISODate("2014-01-26T18:28:27Z"), "title" : "my post 2", "body" : "spost body", "_id" : ObjectId("52e5540837fb8bf218b8c625"), "tags" : [ "android", "actionscript", "java" ], "created" : ISODate("2014-01-26T18:29:28.915Z"), "author" : "whisher", "__v" : 0 }
the result should be like
"android", "actionscript", "java","js", "php", "scala"
You can $unwind, and then $group them back
db.collection.aggregate({ $unwind : "$tags" }, {$group:{_id: "$tags"}});
The result would be
{ _id: "android"},
{ _id: "actionscript"},
{ _id: "java"},
{ _id: "js"},
{ _id: "php"},
{ _id: "scala"}
Use the distinct command (reference):
> db.test.distinct("tags")
[ "js", "php", "scala", "actionscript", "android", "java" ]
You could use aggregation if you eventually needed something more complex:
> db.test.aggregate(
{ $project: { tags : 1 } },
{ $unwind : "$tags" },
{ $group : { _id: "$tags" } } );
Results:
[
{
"_id" : "java"
},
{
"_id" : "actionscript"
},
{
"_id" : "android"
},
{
"_id" : "scala"
},
{
"_id" : "php"
},
{
"_id" : "js"
}
]
I'd use $project (reference) to reduce the number of fields being passed through the pipeline though. In the example above, I've used $project to include only the tags for example.