Finding the max date of each id from millions of data in mongodb - mongodb

I have a collection as below and I need to find the max action time of the products in the list whose product_id is given.
In addition, since there are millions of data, it should be as stabilized as possible. Can you help me?
Example data: If productId is 125 or 126
[
{
"_id": "object",
"at": "2022-03-25 05:00:00",
"productId": 125
},
{
"_id": "object",
"at": "2022-03-25 04:00:00",
"productId": 125
},
{
"_id": "object",
"at": "2022-03-24 12:00:00",
"productId": 126
},
{
"_id": "object",
"at": "2022-03-25 08:00:00",
"productId": 127
}
]
Example output:
[
{
"_id": "object",
"productId": 125
"at": "2022-03-25 05:00:00"
},
{
"_id": "object",
"productId": 126,
"at": "2022-03-24 12:00:00"
}
]

Here's one way to get your desired output.
N.B.: There should be an index on "productId".
db.collection.aggregate([
{
"$match": {
"productId": {
"$in": [125, 126]
}
}
},
{
"$group": {
"_id": "$productId",
"newRoot": {
"$top": {
"sortBy": {
"at": -1
},
"output": "$$ROOT"
}
}
}
},
{"$replaceWith": "$newRoot"}
])
Try it on mongoplayground.net.

Related

How can I get only specific object from nested array mongodb

I'm using mongoDB with PHP. I know how to get the document based on product_id, but I need only a specific object from the whole document, I don't know how to get only specific object from nested array based on product_id.
for ex. My expected output is:
products": [
{
"product_id": 547,
"name": "cola",
"quantity": 24
}
]
then make some changes on object p.s update the quantity then update it to the database.
My collection looks like
"_id": {
"$oid": "62ed30855836b16fd38a00b9"
},
"name": "drink",
"products": [
{
"product_id": 547,
"name": "cola",
"quantity": 24
},
{
"product_id": 984,
"name": "fanta",
"quantity": 42
},
{
"product_id": 404,
"name": "sprite",
"quantity": 12
},
{
"product_id": 854,
"name": "water",
"quantity": 35
}
]
}
Try this:
db.getCollection('test').aggregate([
{
"$unwind": "$products"
},
{
"$match": {
"products.product_id": 547
}
},
{
"$replaceRoot": {
"newRoot": {
"$mergeObjects": [
"$$ROOT",
"$products"
]
}
}
},
{
"$project": {
"products": 0
}
}
])
The query gives the following output:
{
"name" : "cola",
"product_id" : 547,
"quantity" : 24
}

MongoDB groupby - pull comma separated values in a field

I want to groupby the collection and want to pull the comma-separated values.
In the below example, I want to group by "type" and want to pull $sum of "total" and all possible unique values of "value" in a field that should be comma seperated.
collection:
[
{
"type": "1",
"value": "value1",
"total": 10
},
{
"type": "1",
"value": "value3",
"total": 20
},
{
"type": "1",
"value": "value3",
"total": 30
},
{
"type": "2",
"value": "value1",
"total": 10
},
{
"type": "2",
"value": "value2",
"total": 20
}
]
The output that I am expecting:
[
{
"type": "1",
"value": "value1,value3",
"total": 60
},
{
"type": "2",
"value": "value1,value2",
"total": 30
}
]
Please help to provide the approach or code.
This can be achieved just with $group and $project aggregation methods:
https://mongoplayground.net/p/230nt_AMFIm
db.collection.aggregate([
{
$group: {
_id: "$type",
value: {
$addToSet: "$value"
},
total: {
$sum: "$total"
}
},
},
{
$project: {
_id: 0,
type: "$_id",
value: "$value",
total: "$total"
}
},
])

Combining unique elements of arrays without $unwind

I would like to get the unique elements of all arrays in a collection. Consider the following collection
[
{
"collection": "collection",
"myArray": [
{
"name": "ABC",
"code": "AB"
},
{
"name": "DEF",
"code": "DE"
}
]
},
{
"collection": "collection",
"myArray": [
{
"name": "GHI",
"code": "GH"
},
{
"name": "DEF",
"code": "DE"
}
]
}
]
I can achieve this by using $unwind and $group like this:
db.collection.aggregate([
{
$unwind: "$myArray"
},
{
$group: {
_id: null,
data: {
$addToSet: "$myArray"
}
}
}
])
And get the output:
[
{
"_id": null,
"data": [
{
"code": "GH",
"name": "GHI"
},
{
"code": "DE",
"name": "DEF"
},
{
"code": "AB",
"name": "ABC"
}
]
}
]
However, the array "myArray" will have a lot of elements (about 6) and the number of documents passed into this stage of the pipeline will be about 600. So unwinding the array would give me a total of 3600 documents being processed. I would like to know if there's a way for me to achieve the same result without unwinding
You can use below aggregation
db.collection.aggregate([
{ "$group": {
"_id": null,
"data": { "$push": "$myArray" }
}},
{ "$project": {
"data": {
"$reduce": {
"input": "$data",
"initialValue": [],
"in": { "$setUnion": ["$$this", "$$value"] }
}
}
}}
])
Output
[
{
"_id": null,
"data": [
{
"code": "AB",
"name": "ABC"
},
{
"code": "DE",
"name": "DEF"
},
{
"code": "GH",
"name": "GHI"
}
]
}
]

Extracting Particular object from MongoDB from nested Object Array in Document

I have this collection in MongoDB in this Structure.Now I need to query the on this data to get the relatedPeople with weight 60. I searched on this but found noting specific most query give data using $ symbol but it gives you rootnode but not the info that which nested node is maching.
{
"_id": "7686348264868327",
"Name": "myName",
"phoneNo": "12434576896",
"ExtraDetails": {
"TotalPeople": 10,
"activePeople": 8,
"lostPeople": 2,
"relatedPeople": [{
"Name": "reev",
"Relation": "Father",
"Weight": 60
},
{
"Name": "magen2",
"Relation": "Mother",
"Weight": 60
},
{
"Name": "neo",
"Relation": "Gardian",
"Weight": 70
}
]
}
}
{
"_id": "76866898698798",
"Name": "myName2",
"phoneNo": "867867868",
"ExtraDetails": {
"TotalPeople": 8,
"activePeople": 6,
"lostPeople": 2,
"relatedPeople": [{
"Name": "amazing",
"Relation": "Father",
"Weight": 60
},
{
"Name": "caring",
"Relation": "Mother",
"Weight": 90
},
{
"Name": "neo",
"Relation": "Gardian",
"Weight": 75
}
]
}
}
The Output Should be Something Like This
"relatedPeople":[
{
"Name": "reev",
"Relation": "Father",
"Weight": 60
},
{
"Name": "magen2",
"Relation": "Mother",
"Weight": 60
},
{
"Name": "amazing",
"Relation": "Father",
"Weight": 60
}
]
Or
[{
"Name": "reev",
"Relation": "Father",
"Weight": 60
},
{
"Name": "magen2",
"Relation": "Mother",
"Weight": 60
},
{
"Name": "amazing",
"Relation": "Father",
"Weight": 60
}]
You can try following solution:
db.collection.aggregate([
{ $match: { "ExtraDetails.relatedPeople.Weight": 60 } },
{ $project: { "ExtraDetails.relatedPeople": 1 } },
{ $unwind: "$ExtraDetails.relatedPeople" },
{ $match: { "ExtraDetails.relatedPeople.Weight": 60 } },
{ $replaceRoot: { newRoot: "$ExtraDetails.relatedPeople" } }
])
I'm using $unwind to query relatedPeople as a separate documents in $match and $replaceRoot to get rid of nestings.
Alternatively, to get first expected shape you can use $group with $push:
db.collection.aggregate([
{ $match: { "ExtraDetails.relatedPeople.Weight": 60 } },
{ $project: { "ExtraDetails.relatedPeople": 1 } },
{ $unwind: "$ExtraDetails.relatedPeople" },
{ $match: { "ExtraDetails.relatedPeople.Weight": 60 } },
{
$group: {
_id: null,
relatedPeople: { $push: "$ExtraDetails.relatedPeople" }
}
},
{ $project: { _id: 0 } }
])

MongoDB projection. Operator $add field|expression array awareness or after $slice

I've got collection that looks like:
[{
"org": "A",
"type": "simple",
"payFor": 3,
"price": 100
},
{
"org": "A",
"type": "custom",
"payFor": 2,
"price": 115
},
{
"org": "B",
"type": "simple",
"payFor": 1,
"price": 110
},
{
"org": "B",
"type": "custom",
"payFor": 2,
"price": 200
},
{
"org": "B",
"type": "custom",
"payFor": 4,
"price": 220
}]
And need to produce result with query to perform group by "org" where payments appears for only first "payFor" prices in "type".
I'm trying to use expression result by $slice operator in $add but this is not works.
pipeline:
[{
"$group": {
"_id": {
"org": "$org",
"type": "$type"
},
"payFor": {
"$max": "$payFor"
},
"count": {
"$sum": 1
},
"prices": {
"$push": "$price"
}
}
},
{
"$group": {
"_id": "$_id.org",
"payments": {
"$push": {
"type": "$_id.type",
"forFirst": "$payFor",
"sum": {
"$cond": [
{
"$gte": [
"$payFor",
"$count"
]
},
{
"$add": {
"$prices": {
"$slice": "$count"
}
}
},
{
"$add": "$prices"
}
]
}
}
}
}
}]
I know that it is possible to traverse unwinded prices and pick only "payFor" count of them. but result collections are more rich than in example above and this operation will produce some unecessary overheads.
Need some advice from community. Please. Thanks.