How to get multiple documents from one document in mongoDB? - mongodb

I have multiple documents that needs to be queried from mongodb. Requirement is such that I need the nested array of documents has to be in a separate document under certain conditions. I have given a document sample for instance. In that I have an array of objects called cars, the output have to be such that the status is still inprogress and the key: parent_company is true then the objects that has parent_company_id equal to the _id of the parent_company: true and at least one of their model array has "v12".
This might be confusing when explaining but please check on the document in db and the expected result, you'd get an idea on the requirement here.
If you take a look at the second JSON below, you can see those are the same Documents with different array of cars with certain conditions and that is how am expecting the results to be from the actual data from a collection
So the condition is status has to be "inprogress" for "parent_company" : true and if any object under cars array has v12 in model then I need to get those documents that has the same parent_company_id.
Documents in db:
{
"_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
"name" : "A",
"description" : null,
"cars" : [
{
"id" : "63a8808c52f40e1d48a3d1da",
"owner" : "John Doe",
"purchase_date" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
]
},
{
"id" : "63a880a552f40e1d48a3d1dc",
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_company" : false,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
"v12"
]
},
{
"id" : "63a880f752f40e1d48assddd"
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_company" : false,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
]
},
{
"id" : "63a880f752f40e1d48a3d207"
"owner" : "John Doe 11",
"dt" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a880f752f40e1d48a3d207",
"model" : [
"v12"
]
},
{
"id" : "63a880f752f40e1d48agfddd"
"owner" : "John Doe 112",
"dt" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a880f752f40e1d48agfddd",
"model" : [
]
}
]
}
Result I need
[
{
"_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
"name" : "A",
"description" : null,
"cars" : [
{
"id" : "63a8808c52f40e1d48a3d1da",
"owner" : "John Doe",
"purchase_date" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
]
},
{
"id" : "63a880a552f40e1d48a3d1dc",
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_company" : false,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
"v12"
]
},
{
"id" : "63a880f752f40e1d48assddd"
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_company" : false,
"parent_company_id" : "63a8808c52f40e1d48a3d1da",
"model" : [
]
}
]
},
{
"_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
"name" : "A",
"description" : null,
"cars" : [
{
"id" : "63a880f752f40e1d48a3d207"
"owner" : "John Doe 11",
"dt" : "2022-12-25,
"status" : "inprogress",
"parent_company" : true,
"parent_company_id" : "63a880f752f40e1d48a3d207",
"model" : [
"v12"
]
}
]
}
]

If I understand correctly, here's one way to do it.
db.collection.aggregate([
{"$unwind": "$cars"},
{
"$group": {
"_id": "$cars.parent_company_id",
"root": {"$first": "$$ROOT"},
"cars": {"$push": "$cars"}
}
},
{
"$replaceWith": {
"$mergeObjects": [
"$root",
{"cars": "$cars"}
]
}
},
{
"$match": {
"cars.parent_company": true,
"cars.model": "v12"
}
}
])
Try it on mongoplayground.net.

Related

How to query embedded array of objects based on conditions in mongodb

I have an array of objects embedded in a document and there are multiple such documents in an collection.
How to do I query those embedded array of objects with below conditions(based on the documents I have below).
First get objects whose "status" is "active"(status will not be in all the objects but only few)
Then get the "parent_user_id" of the above satisfied object and match it with the rest of the objects "parent_user_id" and get those objects
the result of the above conditions have to set instead of the original Array (i.e: "users") of objects in the output instead of all the objects present.
So if you take a look at the result am expecting there are 3 elements missing from the user array because those elements did not satisfy the above conditions.
Document I have in collection(there will be multiple document as such)
{
"_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
"name" : "A",
"description" : null,
"users" : [
{
"id" : "63a8808c52f40e1d48a3d1da",
"owner" : "John Doe",
"purchase_date" : "2022-12-25,
"status" : "active",
"parent_user_id" : "63a8808c52f40e1d48a3d1da",
"recent_items": ["tomato",onion]
},
{
"id" : "63a880a552f40e1d48a3d1dc",
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_user_id" : "63a8808c52f40e1d48a3d1da",
"recent_items": ["onion"]
},
{
"id" : "63a880f752f40e1d48assddd"
"owner" : "John Doe 2",
"purchase_date" : "2022-12-25,
"parent_user_id" : "63a8808c52f40e1d48a3d1da",
},
{
"id" : "63a880f752f40e1d48a3d207"
"owner" : "John Doe 11",
"dt" : "2022-12-25,
"status" : "inactive",
"parent_user_id" : "63a880f752f40e1d48a3d207",
},
{
"id" : "63a880f752f40e1d48agfmmb"
"owner" : "John Doe 112",
"dt" : "2022-12-25,
"status" : "active",
"parent_user_id" : "63a880f752f40e1d48agfmmb",
"recent_items": ["tomato"]
}
{
"id" : "63a880f752f40e1d48agggg"
"owner" : "John SS",
"dt" : "2022-12-25,
"status" : "inactive",
"parent_user_id" : "63a880f752f40e1d48agggg",
}
{
"id" : "63a880f752f40e1d487777"
"owner" : "John SS",
"dt" : "2022-12-25,
"parent_user_id" : "63a880f752f40e1d48agggg",
}
]
}
Result am expecting
{
"_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
"name" : "A",
"description" : null,
"users" : [
{
"id" : "63a8808c52f40e1d48a3d1da",
"owner" : "John Doe",
"purchase_date" : "2022-12-25,
"status" : "active",
"parent_user_id" : "63a8808c52f40e1d48a3d1da",
"recent_items": ["tomato",onion]
},
{
"id" : "63a880a552f40e1d48a3d1dc",
"owner" : "John Doe 1",
"purchase_date" : "2022-12-25,
"parent_user_id" : "63a8808c52f40e1d48a3d1da",
},
{
"id" : "63a880f752f40e1d48assddd"
"owner" : "John Doe 2",
"purchase_date" : "2022-12-25,
"parent_user_id" : "63a8808c52f40e1d48a3d1da",
},
{
"id" : "63a880f752f40e1d48agfmmb"
"owner" : "John Doe 112",
"dt" : "2022-12-25,
"status" : "active",
"parent_user_id" : "63a880f752f40e1d48agfmmb",
"recent_items": ["tomato"]
}
]
}
i would use some $filter stages as follows :
db.collection.aggregate([
{
$addFields: {
users_matched: {
$filter: {
input: "$users",
as: "user",
cond: {
$eq: [
"active",
"$$user.status"
],
},
},
},
},
},
{
$set: {
users: {
$filter: {
input: "$users",
as: "user",
cond: {
$in: [
"$$user.parent_user_id",
"$users_matched.id"
],
},
},
},
},
},
{
$unset: "users_matched"
}
])
You can check for yourself on mongoplayground https://mongoplayground.net/p/SrpsWb4v21x
EDIT TO ANSWER THE SECOND QUESTION:
You could fix your tomato problem as follows :
db.collection.aggregate([
{
$addFields: {
active_users: {
$filter: {
input: "$users",
as: "user",
cond: {
$eq: [
"active",
"$$user.status"
],
},
},
},
tomato_users: {
$filter: {
input: "$users",
as: "user",
cond: {
$in: [
"tomato",
{
"$ifNull": [
"$$user.recent_items",
[]
]
}
],
},
},
}
},
},
{
$set: {
users: {
$filter: {
input: "$users",
as: "user",
cond: {
$and: [
{
$in: [
"$$user.parent_user_id",
"$active_users.id"
],
},
{
$in: [
"$$user.parent_user_id",
"$tomato_users.parent_user_id"
],
}
]
},
},
},
},
},
{
$unset: [
"active_users",
"tomato_users"
]
}
])
See on mongoplayground https://mongoplayground.net/p/mb21UT475yt

Find a nested object field inside an array in mongodb aggregate

I have this object as below.
{
"_id" : ObjectId("5ec80a981e89a84b19934039"),
"status" : "active",
"organizationId" : "1",
"productId" : "1947",
"name" : "BOOKEND & PAPER WEIGHT SET – ZODIAC PIG – RED COPPER + PLATINUM",
"description" : "This global exclusive Zodiac bookend and paperweight set from Zuny will stand auspiciously on your bookcase and table, spreading good luck and fortune throughout your home just in time for the Year of the Pig.",
"brand" : "ZUNY",
"created" : "2018-09-28 00:00:00",
"updated" : "2020-05-22 09:19:07",
"mainImage" : "https://",
"availableOnline" : true,
"colors" : [
{
"images" : [
{
"type" : "studio",
"url" : "https://"
},
{
"type" : "studio",
"url" : "https://"
},
{
"type" : "studio",
"url" : "https://"
}
],
"extraInfo" : [
{
"type" : "text-tag",
"title" : "CATEGORY",
"tags" : [
"HOME FURNISHING & DÉCOR",
"LIFESTYLE"
]
},
{
"type" : "text-tag",
"title" : "BRAND",
"tags" : [
"ZUNY"
]
},
{
"type" : "text-tag",
"title" : "COLOUR",
"tags" : [
"GOLD",
"ROSE GOLD"
]
},
{
"type" : "text-tag",
"title" : "SEASON",
"tags" : [
"AW(2018)"
]
},
{
"type" : "text-tag",
"title" : "HASHTAG",
"tags" : [
"BOOKCASES",
"BOOKEND",
"COLOUR",
"EXCLUSIVE",
"GLOBAL EXCLUSIVE",
"HOME",
"LEATHER",
"MOTIF",
"OBJECTS",
"PAPER",
"PAPERWEIGHT",
"PLATINUM",
"SET",
"SYNTHETIC",
"ZODIAC",
"HANDMADE",
"time"
]
}
],
"_id" : ObjectId("5ec80a981e89a84b1993403a"),
"colorId" : "1",
"color" : "ROSE GOLD",
"status" : "active",
"sizes" : [
{
"extraInfo" : [
{
"type" : "text-block",
"title" : "Size And Fit",
"text" : ""
},
{
"type" : "text-block",
"title" : "Information",
"text" : "Global exclusive. Colour: Copper/Platinum. Set includes: Zodiac Pig bookend (x 1), Zodiac Pig paperweight (x 1). Metallic copper- and platinum-tone synthetic leather. Pig motif. Iron pellet filling. Handmade"
}
],
"_id" : ObjectId("5ec80a981e89a84b1993403b"),
"sizeId" : "1",
"neo" : "0210111790664",
"size" : "*",
"originalPrice" : "1060.00",
"sellingPrice" : "1060.00",
"discountPercent" : "0.00",
"url" : "https://",
"status" : "active",
"currency" : "HK$",
"stores" : [
{
"storeId" : "1",
"quantity" : 70,
"_id" : ObjectId("5ec80a981e89a84b1993403c"),
"available" : 70,
"reserved" : 0,
"name" : "Park Street",
"status" : "active"
},
{
"storeId" : "2",
"quantity" : 95,
"_id" : ObjectId("5ec80a981e89a84b1993403d"),
"name" : "Rashbehari",
"status" : "active"
}
]
}
]
}
],
"__v" : 0
}
I want the output as follows
{
"name": "Mock Collection",
"collectionId": "92",
"products": [
{
"title": "GLOBAL EXCLUSIVE OFF-SHOULDER SHIRT DRESS",
"imageUrl": "https://",
"productId": "21174",
"currency": "" // This should be this.colors[0].sizes[0].currency
},
]
}
How to get the nested field. I tried using arrayElemAt by which I was able to get to colors[0]. But I am confused how to get inside the nested object of sizes from there. Also the currency node should have the exact value. It comes like currency:{currency: value} which I don't want.
Please help!
Not sure how you've got that output but to extract currency from first object of sizes then you need to try this :
db.collection.aggregate([
{
$project: {
currency: {
$arrayElemAt: [
{
$arrayElemAt: [ "$colors.sizes.currency", 0 ] // gives an array of currency values, in your case since you've only one object just an array of one value
},
0
]
}
}
}
])
Test : mongoplayground

MOngoDB query to groupby with different fields based on condition to return the latest record

I want to groupby based on condition where my target field can be sender.category or reciever.category based on condition that either of those field belongs to "cat1", and get the last record of each of on sender.id or reciever.id based on createdAt.
Sample Json1:
{
"code" : "34242342",
"name" : "name1",
"amount" : 200,
"sender" : {
"id" : "fsrfsr3242",
"name" : "name2",
"phone" : "12345678",
"category": "cat1"
},
"receiver" : {
"id" : "42342rewr",
"name" : "naem3",
"phone" : "5653679755",
"category": "cat2"
},
"message" : "",
"status" : "done",
"createdAt" : "2019-09-27T09:17:32.597Z"
}
Sample Json2:
{
"code" : "34242342",
"name" : "name1",
"amount" : 200,
"sender" : {
"id" : "fsrfsr3242",
"name" : "name2",
"phone" : "12345678",
"category": "cat3"
},
"receiver" : {
"id" : "42342rewr",
"name" : "naem3",
"phone" : "5653679755",
"category": "cat1"
},
"message" : "",
"status" : "done",
"createdAt" : "2019-09-27T09:17:32.597Z"
}
Query:
[{$match: {
$or: [{ "sender.category": 'cat1' }, {"receiver.category" : 'cat1'}]
}}, {$sort: {
"createdAt": 1
}}, {$group: {
_id: {sender :"$sender.id", reciever : "$receiver.id"},
lastrecord: {
$last: "$$ROOT"
}
}}]
I want to return only the last record, sender.id or receiver.id can have multiple records of which i only want to retrieve the last one. But my query is returning multiple records.
How to get only the last i.e latest one based on above conditions and createdAt?
Sample output:
{
"lastrecord" : {
"name" : "name1",
"amount" : 1000,
"sender" : {
"name" : "name2",
"phone" : "213232141",
"category" : "cat1"
},
"receiver" : {
"name" : "name",
"phone" : "321312412",
"category" : "cat2"
},
"status" : "done",
"createdAt" : "2019-11-25T17:00:17.226+06:30"
}
}
i want this for every sender.id or receiver.id

mongodb find $elemMatch with Multiple Fields

everyone. I need your help. For a script I have to search for users by their ldap id, but I have the problem that I get no output when searching.
a user has the following output.
db.users.find({"name" : "John Sample"} ).toArray()
[
{
"_id" : "testid",
"createdAt" : ISODate("2017-05-11T13:49:35.125Z"),
"services" : {
"password" : {
"bcrypt" : ""
},
"ldap" : {
"id" : "12345678",
"idAttribute" : "uid"
},
"resume" : {
"loginTokens" : [ ]
}
},
"username" : "john",
"emails" : [
{
"address" : "john.sample#test.com",
"verified" : true
}
],
"type" : "user",
"status" : "offline",
"active" : true,
"name" : "John Sample",
"_updatedAt" : ISODate("2018-07-05T18:44:22.061Z"),
"roles" : [
"user"
],
"ldap" : true,
"lastLogin" : ISODate("2018-07-05T10:33:00.712Z"),
"statusConnection" : "offline",
"utcOffset" : 2,
"statusDefault" : "offline"
}
]
I used this command but without success.
db.users.find({"services" : {"$elemMatch": {"ldap" : {"$elemMatch": {"id" : "12345678"}}}}}} ).toArray();
[ ]
$elemMatch is used to find elements that match criteria in an array. But services is an document (sub document), not an array. Just use dot notation to query :
db.users.find({"services.ldap.id":"12345678"})

mongodb Can't get the query to work

I'm trying to do a query in mongodb but I can't get it to work.
My document looks something like this.
{
"_id" : ObjectId("5305e54133e65b7341d63af3"),
"clients" : [
{
"aggregations" : {
"department" : [
"department1",
"department3"
],
"customer" : "customer2"
},
"lastLogin" : ISODate("2014-02-26T09:41:56.445Z"),
"locale" : "en"
"name" : "Test",
"validFrom" : null,
"validTo" : null,
"visiting" : {
"phone" : "031-303030",
"company" : "MyCompany",
"office" : [
"jag är ett test",
"lite mer data"
],
"country" : "Norge"
}
},
{
"approvedEmailSent" : true,
"lastLogin" : ISODate("2014-03-01T15:27:12.252Z"),
"locale" : "en",
"name" : "Test2",
"visiting" : {
"phone" : "031-307450",
"company" : "Other Company",
"branch" : "Advertising agency"
}
}
],
"firstname" : "Greger",
"lastname" : "Aronsson",
"username" : "TheUsername"
}
As you can see a user can have many clients. They are matched by name. The clients have visiting.company but sometimes this will not be the case.
I want to query where the clients.name is Test and regexp for visting.company and also firstname, lastname. If I'm logged in at Test2 I don't want hits on visiting.company "MyCompany". Hope this makes sense!
You can write query like :
db.visitCompany2.find({ $or : [
{'clients.name': 'Test2'}, //Company name
{'clients.visiting.company': {
$regex: /Other/g //Your visiting company regex
}},
{firstname: "Greger"},
{"lastname": "Aronsson}"
]}, {
'clients.$': 1, //projection for clients
firstname: 1,
lastname: 1
});
Output:
{
"_id": ObjectId("5305e54133e65b7341d63af3"),
"clients": [{
"approvedEmailSent": true,
"lastLogin": ISODate("2014-03-01T15:27:12.252Z"),
"locale": "en",
"name": "Test2",
"visiting": {
"phone": "031-307450",
"company": "Other Company",
"branch": "Advertising agency"
}
}],
"firstname": "Greger",
"lastname": "Aronsson"
}