MongoDB query subarray in sub array - arrays

i want fetch a unitHouse from my document which is an sub array of sub array
Here is the data
{
"_id" : ObjectId("5a17d305c438324308bffb19"),
"floorRow" : [
{
"floorRowNo" : "F1",
"floorRowInfo" : "Best Floor Ever that i have ever seen",
"_id" : ObjectId("5a17d333c438324308bffb1a"),
"unitHouse" : [
]
},
{
"floorRowNo" : "F2",
"floorRowInfo" : "view",
"_id" : ObjectId("5a1bdfbb4d63841c3cb6fc89"),
"unitHouse" : [
{
"unitHouseNo" : "Unit001",
"unitHouseType" : "OFFICE",
"unitHouseStatus" : "SELL",
"_id" : ObjectId("5a1d212bed3a552f0421fd6b"),
},
{
"unitHouseNo" : "Unit002",
"unitHouseType" : "CAT003",
"unitHouseStatus" : "SELL",
"_id" : ObjectId("5a1e3691af12544ff05690e3"),
}
]
}
],
}
Here is what I have queried so far, which i can get floor F2 that i wanted, but it came with both unit. I want only unitHouse with id : 5a1e3691af12544ff05690e3.
propertyDevModel.aggregate([
{
$match: {
_id: mongoose.Types.ObjectId("5a17d305c438324308bffb19"),
}
},
{
$project: {
floorRow: {
$filter: {
input: '$floorRow',
as: 'floorRow',
cond: {
$eq: ['$$floorRow._id', mongoose.Types.ObjectId("5a1bdfbb4d63841c3cb6fc89")],
}
}
}
}
},
])

I have answered this q by myself, but i will keep this post for others who have the same problem.
db.aggregate([
{
$match: {
_id: projectId,
'floorRow._id': floorRowId
}
},
{$unwind: '$floorRow'},
{
$match: {
'floorRow._id': floorRowId
}
},
{$unwind: '$floorRow.unitHouse'},
{
$match: {
'floorRow.unitHouse._id': unitId
}
},
{
$project:{
'floorRow.unitHouse': 1
}
}
])

Related

MongoDB merge Array Elements inside an Array

I have a collection.
{
"_id" : "410a7cb2-7ee1-4e7a-9fb7-fa651fcaa4e5",
"reqHistoryEvents" : [
{
"reqHistoryMsg" : "abcd",
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:18:30.850+0000"),
},
{
"reqHistoryMsg" : "EFGH ",
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:22:12.716+0000"),
},
{
"reqHistoryMsg" : "IJKL",
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:22:12.716+0000"),
}
]
}
I want to convert it to this :::::
{
"_id" : "410a7cb2-7ee1-4e7a-9fb7-fa651fcaa4e5",
"reqHistoryEvents" : [
{
"reqHistoryMsg" : "abcd",
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:18:30.850+0000"),
},
{
"reqHistoryMsg" : ["EFGH ","IJKL"],
"reqHistoryCreatedAt" : ISODate("2022-04-27T08:22:12.716+0000"),
}
]
}
Basically it will be based on the creation Timestamp. We need to merge the reqHistoryMsg if we have same reqHistoryCreatedAt.
I am not able to write the mongo query. Any help?
$unwind - Deconstruct reqHistoryEvents array field.
$group - Group by _id and reqHistoryEvents.reqHistoryCreatedAt fields. Add reqHistoryMsg into an array.
$group - Group by _id field and form reqHistoryEvents array.
db.collection.aggregate([
{
$unwind: "$reqHistoryEvents"
},
{
$group: {
_id: {
_id: "$_id",
reqHistoryCreatedAt: "$reqHistoryEvents.reqHistoryCreatedAt"
},
reqHistoryMsg: {
$push: "$reqHistoryEvents.reqHistoryMsg"
}
}
},
{
$group: {
_id: "$_id._id",
reqHistoryEvents: {
$push: {
reqHistoryMsg: "$reqHistoryMsg",
reqHistoryCreatedAt: "$_id.reqHistoryCreatedAt"
}
}
}
}
])
Sample Mongo Playground

How to query on embedded documents

{
"_id" : ObjectId("5fa919a49bbe481d117506c9"),
"isDeleted" : 0,
"productId" : 31,
"references" : [
{
"_id" : ObjectId("5fa919a49bbe481d117506ca"),
"languageCode" : "en",
"languageId" : 1,
"productId" : ObjectId("5fa919a49bbe481d117506ba")
},
{
"_id" : ObjectId("5fa91cc7d7d52f1e389dee1f"),
"languageCode" : "ar",
"languageId" : 2,
"productId" : ObjectId("5fa91cc7d7d52f1e389dee1e")
}
],
"createdAt" : ISODate("2020-11-09T10:27:48.859Z"),
"updatedAt" : ISODate("2020-11-09T10:27:48.859Z"),
"__v" : 0
},
{
"_id" : ObjectId("5f9aab1d8e475489270ebe3a"),
"isDeleted" : 0,
"productId" : 21,
"references" : [
{
"_id" : ObjectId("5f9aab1d8e475489270ebe3b"),
"languageCode" : "en",
"languageId" : 1,
"productId" : ObjectId("5f9aab1c8e475489270ebe2d")
}
],
"createdAt" : ISODate("2020-10-29T11:44:29.852Z"),
"updatedAt" : ISODate("2020-10-29T11:44:29.852Z"),
"__v" : 0
}
This is my mongoDB collection in which i store the multilingual references to product collection. In productId are the references to product Collection. Now If we have ar in our request, then we will only have the productId of ar languageCode. If that languageCode does not exist then we will have en langCode productId.
For Example if the user pass ar then the query should return
"productId" : ObjectId("5fa91cc7d7d52f1e389dee1e")
"productId" : ObjectId("5f9aab1c8e475489270ebe2d")
I have tried using $or with $elemMatch but I am not able to get the desired result. Also i am thinking of using $cond. can anyone help me construct the query.
We can acheive
$facet helps to categorized the incoming documents
In the arArray, we get all documents which has"references.languageCode": "ar" (This document may or may not have en), then de-structure the references array, then selecting the "references.languageCode": "ar" only using $match. $group helps to get all productIds which belong to "references.languageCode": "ar"
In the enArray, we only get documents which have only "references.languageCode": "en". Others are same like arArray.
$concatArrays helps to concept both arArray,enArray arrays
$unwind helps to de-structure the array.
$replaceRoot helps to make the Object goes to root
Here is the mongo script.
db.collection.aggregate([
{
$facet: {
arAarray: [
{
$match: {
"references.languageCode": "ar"
}
},
{
$unwind: "$references"
},
{
$match: {
"references.languageCode": "ar"
}
},
{
$group: {
_id: "$_id",
productId: {
$addToSet: "$references.productId"
}
}
}
],
enArray: [
{
$match: {
$and: [
{
"references.languageCode": "en"
},
{
"references.languageCode": {
$ne: "ar"
}
}
]
}
},
{
$unwind: "$references"
},
{
$group: {
_id: "$_id",
productId: {
$addToSet: "$references.productId"
}
}
}
]
}
},
{
$project: {
combined: {
"$concatArrays": [
"$arAarray",
"$enArray"
]
}
}
},
{
$unwind: "$combined"
},
{
"$replaceRoot": {
"newRoot": "$combined"
}
}
])
Working Mongo playground
You can test this solution to see if it is useful for you question:
db.collection.aggregate([
{
$addFields: {
foundResults:
{
$cond: {
if: { $in: ["ar", "$references.languageCode"] }, then:
{
$filter: {
input: "$references",
as: "item",
cond: {
$and: [{ $eq: ["$$item.languageCode", 'ar'] },
]
}
}
}
, else:
{
$filter: {
input: "$references",
as: "item",
cond: {
$and: [{ $eq: ["$$item.languageCode", 'en'] },
]
}
}
}
}
}
}
},
{ $unwind: "$foundResults" },
{ $replaceRoot: { newRoot: { $mergeObjects: ["$foundResults"] } } },
{ $project: { _id: 0, "productId": 1 } }
])

MongoDB joining across array of ids

Before the question, I'm extremely new to mongo DB and NoSQL.
I'm having two collections in my database:
users:
{
"_id" : ObjectId("5f1efeece50f2b25d4be2de2"),
"name" : {
"familyName" : "Doe",
"givenName" : "John"
},
"email" : "johndoe#example.com",
"threads" : [ObjectId("5f1f00f31abb0e3f107fbf93"), ObjectId("5f1f0725850eca800c70ef9e") ] }
}
threads:
{
"_id" : ObjectId("5f1f0725850eca800c70ef9e"),
"thread_participants" : [ ObjectId("5f1efeece50f2b25d4be2de2"), ObjectId("5f1eff1ae50f2b25d4be2de4") ],
"date_created" : ISODate("2020-07-27T16:25:19.702Z") }
}
I want to get all the threads which an user is involved in with the other user's info nested inside.
Something like:
{
"_id" : ObjectId("5f1f0725850eca800c70ef9e"),
"thread_participants" :
[
{
"name" : {
"familyName" : "Doe",
"givenName" : "John"
},
"email" : "johndoe#example.com",
},
{
"name" : {
"familyName" : "Doe",
"givenName" : "Monica"
},
"email" : "monicadoe#example.com",
}
],
"date_created" : ISODate("2020-07-27T16:25:19.702Z") }
},
...,
...,
...
How do I go about this?
You can use $lookup to "join" the data from both collections:
db.threads.aggregate([
{
$lookup: {
from: "$users",
let: { participants: "$thread_participants" },
pipeline: [
{
$match: {
$expr: {
$in: [ "$_id", "$$participants" ]
}
}
},
{
$project: {
_id: 1,
email: 1,
name: 1
}
}
],
as: "thread_participants"
}
}
])
Mongo Playground

Querying Arrays in MongoDB

I have a Mongo collection called players and in each document there are two entries called transactions and autographs. Both are arrays with objects inside containing a timestamp.
How can I use this db.collection.count( { timestamp: {$gt: 1585526400000} }) to display how many have been inputed into the db in the last 7 days?
Assuming the following two simplified records are in your database:
{
"_id" : ObjectId("5e8b8b66c1f8161eeeab762f"),
"transactions" : [
{
"timestamp" : ISODate("2020-04-05T00:25:20.202Z")
},
{
"timestamp" : ISODate("2020-04-02T00:25:20.202Z")
},
{
"timestamp" : ISODate("2020-04-01T00:25:20.202Z")
},
{
"timestamp" : ISODate("2020-01-06T00:25:20.202Z")
}
]
},
{
"_id" : ObjectId("5e8b9008b29982222cd38888"),
"transactions" : [
{
"timestamp" : ISODate("2020-04-04T00:25:20.202Z")
},
{
"timestamp" : ISODate("2020-02-03T00:25:20.202Z")
},
{
"timestamp" : ISODate("2020-02-01T00:25:20.202Z")
},
{
"timestamp" : ISODate("2020-02-06T00:25:20.202Z")
}
]
}
Then you can get the count of the array elements which your condition as follows:
db.getCollection('players').aggregate([{
$project: {
transactionsCount: {
$size: {
$filter: {
input: "$transactions",
as: "item",
cond: {
$gte: ["$$item.timestamp", ISODate('2020-03-30 00:00:00.000Z')]
}
}
}
}
}
}
])
Result:
{
"_id" : ObjectId("5e8b8b66c1f8161eeeab762f"),
"transactionsCount" : 3
}
{
"_id" : ObjectId("5e8b9008b29982222cd38888"),
"transactionsCount" : 1
}

Mongo DB array aggregation to count all array entries in a collection [duplicate]

so i have a bunch of simple documents like
{
"foos": [
ObjectId("5105862f2b5e30877c685c58"),
ObjectId("5105862f2b5e30877c685c57"),
ObjectId("5105862f2b5e30877c685c56"),
],
"typ": "Organisation",
}
and i want to find out the overall size of associated foos to documents of type "Organisation"
so i have this aggregate query
db.profil.aggregate(
[
{
$match:{
"typ":"Organisation"
}
},
{
$project: {
fooos: { $size: "$foos" }
}
}
]
)
this returns the count of all foos for each document
like :
{ "_id" : ObjectId("50e577602b5e05e74b38a6c8"), "foooos" : 1 }
{ "_id" : ObjectId("51922170975a09f363e3eef5"), "foooos" : 3 }
{ "_id" : ObjectId("51922170975a09f363e3eef8"), "foooos" : 2 }
{ "_id" : ObjectId("5175441d975ae346a3a8dff2"), "foooos" : 0 }
{ "_id" : ObjectId("5192216f975a09f363e3eee9"), "foooos" : 2 }
{ "_id" : ObjectId("5192216f975a09f363e3eeeb"), "foooos" : 3 }
{ "_id" : ObjectId("5192216f975a09f363e3eee4"), "foooos" : 2 }
{ "_id" : ObjectId("5192216f975a09f363e3eee6"), "foooos" : 2 }
{ "_id" : ObjectId("5192216f975a09f363e3eedb"), "foooos" : 2 }
{ "_id" : ObjectId("51922174975a09f363e3ef4a"), "foooos" : 1 }
{ "_id" : ObjectId("5192216f975a09f363e3eee1"), "foooos" : 1 }
{ "_id" : ObjectId("5192216e975a09f363e3eed7"), "foooos" : 2 }
{ "_id" : ObjectId("5192216f975a09f363e3eeee"), "foooos" : 3 }
is there some query that would return the summed up count for foos of all documents ?
i played arround with $sum but dont know how to combine with my query, i only do get syntax errors, it would be cool to know if this is possible
Include the $group operator pipeline stage after the $project step as follows:
db.profil.aggregate([
{ "$match":{ "typ": "Organisation" } },
{ "$project": {
"fooos": { "$size": "$foos" }
} },
{ "$group": {
"_id": null,
"count": {
"$sum": "$fooos"
}
} }
])
This will group all the input documents from the previous $project stage and applies the accumulator expression $sum on the fooos field within the group to get the total (using your last example):
This can also be done by-passing the $project pipeline as:
db.profil.aggregate([
{ "$match": { "typ": "Organisation" } },
{ "$group": {
"_id": null,
"count": {
"$sum": { "$size": "$foos" }
}
} }
])
Output
/* 0 */
{
"result" : [
{
"_id" : null,
"count" : 24
}
],
"ok" : 1
}
I know this is an old question but you can bypass project altogether if you want, so how about this?
db.profil.aggregate([
{
"$match":{ "typ": "Organisation" }
},
{
"$group":
{
"_id": null,
"count":
{
"$sum": { "$size": "$foos" }
}
}
}])
The output remains the same and it seems it's (slightly) faster.

Resources