How can I filter if all num of qty greater then 50 then this is return otherwise not:
this is examples documents;
{
_id: ObjectId("5234cc89687ea597eabee675"),
code: "xyz",
tags: [ "school", "book", "bag", "headphone", "appliance" ],
qty: [
{ size: "S", num: 10, color: "blue" },
{ size: "M", num: 45, color: "blue" },
{ size: "L", num: 100, color: "green" }
]
}
{
_id: ObjectId("5234cc8a687ea597eabee676"),
code: "abc",
tags: [ "appliance", "school", "book" ],
qty: [
{ size: "6", num: 100, color: "green" },
{ size: "6", num: 70, color: "blue" },
{ size: "8", num: 100, color: "brown" }
]
}
{
_id: ObjectId("5234ccb7687ea597eabee677"),
code: "efg",
tags: [ "school", "book" ],
qty: [
{ size: "S", num: 10, color: "blue" },
{ size: "M", num: 100, color: "blue" },
{ size: "L", num: 100, color: "green" }
]
}
Is it possiblt with mongodb query? how?
I have tried many ways but didnt work. please help
I expected:
{
_id: ObjectId("5234cc8a687ea597eabee676"),
code: "abc",
tags: [ "appliance", "school", "book"],
qty: [
{ size: "6", num: 100, color: "green" },
{ size: "6", num: 70, color: "blue" },
{ size: "8", num: 100, color: "brown" }
]
}
{
_id: ObjectId("52350353b2eff1353b349de9"),
code: "ijk",
tags: [ "electronics", "school" ],
qty: [
{ size: "M", num: 100, color: "green" }
]
}
If I understood your request correctly you would like to filter on the qty.num field right? If so, use this aggregation pipeline:
var options = {
allowDiskUse: false
};
var pipeline = [
{
"$unwind": {
"path": "$qty"
}
},
{
"$match": {
"qty.num": {
"$gte": 50.0
}
}
},
{
"$group": {
"_id": "$_id",
"code": {
"$first": "$code"
},
"tags": {
"$first": "$tags"
},
"qty": {
"$push": "$qty"
}
}
}
];
var cursor = collection.aggregate(pipeline, options);
I hope this helps. It works for me.
It is confusing as the record with _id: ObjectId("52350353b2eff1353b349de9") does not appear in your sample dataset. Nevertheless, from your description, you may be looking for $allElementsTrue. You can use $map to apply your > 50 criteria to the qty array and feed the result to $allElementsTrue.
db.collection.find({
$expr: {
$allElementsTrue: {
$map: {
input: "$qty",
as: "q",
in: {
$gt: [
"$$q.num",
50
]
}
}
}
}
})
Mongo Playground
Related
i'm trying to distinct different string values of "comment" and "dates" and concatenate them in two different strings one for comments and one for reclamation dates I used $addToSet to distinct values but every time the concatenating is giving empty result
and this is m code :
db.collection.aggregate([
{
$group: {
_id: {
b: "$type"
},
total: {
$sum: 1
},
root: {
$push: "$$ROOT"
}
}
},
{
"$unwind": "$root"
},
{
$group: {
_id: {
r: "$root.situation",
b: "$root.type"
},
cnt: {
$sum: 1
},
total: {
"$first": "$total"
},
}
},
{
$project: {
a: [
{
k: "$_id.r",
v: "$cnt"
}
],
type: "$_id.b",
total: "$total",
_id: 0,
}
},
{
$project: {
d: {
$arrayToObject: "$a"
},
type: 1,
total: 1
}
},
{
$group: {
_id: "$type",
situation: {
$push: "$d"
},
sum: {
"$first": "$total"
},
//add to set of commets and dates
comment: {
$addToSet: "$comment"
},
daterec: {
$addToSet: "$daterec"
},
}
},
{
$project: {
_id: 0,
type: "$_id",
sum: 1,
"options": {
$mergeObjects: "$situation"
},
//concatenating results
comment: {
$reduce: {
input: "$comment",
initialValue: "",
in: {
$cond: [
{
"$eq": [
"$$value",
""
]
},
"$$this",
{
$concat: [
"$$value",
" ",
"$$this"
]
}
]
}
}
},
daterec: {
$reduce: {
input: "$daterec",
initialValue: "",
in: {
$cond: [
{
"$eq": [
"$$value",
""
]
},
"$$this",
{
$concat: [
"$$value",
" ",
"$$this"
]
}
]
}
}
}
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$$ROOT",
"$options"
]
}
}
},
{
$project: {
options: 0,
}
},
])
and this is the output :
{
"after sales management": 4,
"comment": "",
"daterec": "",
"instock": 1,
"sum": 5,
"type": "pc"
}
its always giving "comment" and"daterec": empty while i want it to show the concatenating of distinct strings it should looks something like this :
{
"after sales management": 4,
"comment": "waiting for pieces waiting for approval nothing",
"daterec": "1",//this is just an example beacause all dates are set to "1"
"instock": 1,
"sum": 5,
"type": "pc"
}
this is an example of my work with a collection example:
https://mongoplayground.net/p/dB3xBFsIfun
PS : i think the problem is in the of using the $addToSet insite $group
I need to add the paramater sector as an array in the group () statement.
I have the following code:
await Escaneado.aggregate([
{
$match: {
$and: [
{ "gestion": id },
{ "disponible": true }
]
},
},
{
$group: {
_id: {
code:"$codigo",
quantityTarget:"$cantidadObjetivo",
},
quantityTotalScanded : { $sum: "$cantidad" }
}
},
{
$addFields:{
difference:{ $subtract: ["$quantityTotalScanded", "$_id.quantityTarget"]}
}
},
])
output:
{
"ok": true,
"escaneadosDB": [
{
"_id": {
"code": "0V3011123A00",
"quantityTarget": 36
},
"quantityTotalScanded": 36,
"difference": 0
},
{
"_id": {
"code": "0V3011123B00",
"quantityTarget": 36
},
"quantityTotalScanded": 4,
"difference": -32
},
{
"_id": {
"code": "0V3012121D00",
"quantityTarget": 56
},
"quantityTotalScanded": 56,
"difference": 0
}
]}
output expected:
{
"ok": true,
"escaneadosDB": [
{
"_id": {
"code": "0V3011123A00",
"quantityTarget": 36,
"sector": ["A", "B", "C"]
},
"quantityTotalScanded": 36,
"difference": 0
},
{
"_id": {
"code": "0V3011123B00",
"quantityTarget": 36,
"sector": ["A"]
},
"quantityTotalScanded": 4,
"difference": -32
},
{
"_id": {
"code": "0V3012121D00",
"quantityTarget": 56,
"sector": ["A", "B"]
},
"quantityTotalScanded": 56,
"difference": 0
}
]}
I think I can add it as an array, but i do not know how implement! .
The sectors are different parameters, therefore I cannot use it as "_id". I need total quantity and the sectors in the query.
How could I do this with mongo?
this worked for me:
add this in group() sentence:
sectors: { $push: { sector: "$sector" } }
all code:
await Escaneado.aggregate([
{
$match: {
$and: [
{ "gestion": id },
{ "disponible": true }
]
},
},
{
$group: {
_id: {
code:"$codigo",
quantityTarget:"$cantidadObjetivo",
},
quantityTotalScanded : { $sum: "$cantidad" },
sectors: { $push: { sector: "$sector" } }
}
},
{
$addFields:{
difference:{ $subtract: ["$quantityTotalScanded", "$_id.quantityTarget"]}
}
},
{$sort: {"cantidadTotal": -1}},
I have the following MongoDB schema:
const userSchema = new mongoose.Schema({
email: {
type: String,
required: [true, 'Email is required.']
},
transactions: [
{
categoryName: {
type: String,
required: [true, 'Category name in transaction is required.']
},
categoryType: {
type: String,
required: [true, 'Category type in transaction is required.']
},
amount: {
type: Number,
required: [true, 'Transaction amount is required.']
}
}
]})
transactions.categoryType can only be Income or Expense. Now per queried _id, I want to return the ratio/percentage of transactions.CategoryName per Income and Expense. Meaning if I have the following data:
{
"_id": 000001,
"email": "asdasd#email.com"
"transactions": [
{
"categoryName": "Food",
"categoryType": "Expense",
"amount": 200
},
{
"categoryName": "Rent",
"categoryType": "Expense",
"amount": 1000
},
{
"categoryName": "Salary",
"categoryType": "Income",
"amount": 15000
}
]
}
the result that I would want is:
{ "email": "asdasd#email.com",
"Income": [["Salary", 100]],
"Expense": [["Food", 16.67],["Rent",83.33]],
}
Now, I have the following query:
return User.aggregate([
{ $match: { _id : ObjectId(request.params.id) } },
{ $unwind : "$transactions"},
{ $group : { _id : { type: "$transactions.categoryType" },
total: {$sum : "$transactions.amount"},
transactionsArray: { $push: "$transactions"}
}
},
{ $project: {
_id: 0,
transactionsArray:1,
type: "$_id.type",
total:1
}
}
])
which returns a data like this:
[
{
"total": 1200,
"transactions": [
{
"categoryName": "Food",
"categoryType": "Expense",
"amount": 200,
},
{
"categoryName": "Rent",
"categoryType": "Expense",
"amount": 1000,
}
],
"type": "Expense"
},
{
"total": 15000,
"transactions": [
{
"categoryName": "Salary",
"categoryType": "Income",
"amount": 15000,
}
],
"type": "Income"
}
]
Now, I do not know how am I going to further process the result set to divide the transactions.amount by the total to get the result that I want.
You may go with multiple steps in aggregations
$unwind to deconstruct the array
$group- first group to group by _id and $categoryType. So we can get the total amount and an amount for particular transaction. This helps to calculate the ratio.
$map helps to loop over the array and calculate the ratio
$reduce- You need comma separated string array of objects. So loop it and get the structure.
$group to group by _id only so we can get the key value pair of category type and Income/Expense when we push
$replaceRoot to make the $grp object as root which should be merged with already existing fields ($mergeObjects)
$project for remove unwanted fields
Here is the code
db.collection.aggregate([
{ "$unwind": "$transactions" },
{
"$group": {
"_id": { id: "$_id", catType: "$transactions.categoryType" },
"email": { "$first": "$email" },
"amount": { "$sum": "$transactions.amount" },
"category": {
$push: { k: "$transactions.categoryName", v: "$transactions.amount" }
}
}
},
{
$addFields: {
category: {
$map: {
input: "$category",
in: {
k: "$$this.k",
v: {
"$multiply": [
{ "$divide": [ "$$this.v","$amount" ]},
100
]
}
}
}
}
}
},
{
"$addFields": {
category: {
"$reduce": {
"input": "$category",
"initialValue": [],
"in": {
"$concatArrays": [
[
[ "$$this.k", { $toString: "$$this.v" } ]
],
"$$value"
]
}
}
}
}
},
{
"$group": {
"_id": "$_id.id",
"email": { "$first": "$email" },
"grp": { "$push": { k: "$_id.catType", v: "$category" } }
}
},
{
"$replaceRoot": {
"newRoot": {
"$mergeObjects": [ { "$arrayToObject": "$grp" }, "$$ROOT" ]
}
}
},
{ "$project": { grp: 0 } }
])
Working Mongo playground
I have below array of array inside my document
{
items: [
["Tax", 10, 20, 30],
["FX Adjustments", 10, 20, 30],
["Tax", 10, 20, 30],
["FX Adjustments", 10, 20, 30]
]
}
I need to combine Tax with Tax and FX Adjustments with FX Adjustments.
Output I need
{
items: [
["Tax", 20, 40, 60],
["FX Adjustments", 20, 40, 60]
]
}
I tried but with no luck
db.collection.aggregate([
{
$project: {
items: {
$reduce: {
input: "$items",
initialValue: [],
in: {
$cond: [
]
}
}
}
}
}
])
Kindly help with this
Thank you!!!
You need to start with $unwind and then $group by first array element ($arrayElemAt). Then you can run $reduce like you tried but since your array is multidimensional, you need to wrap it with $map to represent the index. To get back the original data format you can group by null and use $concatArrays to put grouping _id as first array element:
db.collection.aggregate([
{
$unwind: "$items"
},
{
$group: {
_id: { $arrayElemAt: [ "$items", 0 ] },
values: { $push: { $slice: [ "$items", 1, { $size: "$items" } ] } }
}
},
{
$project: {
_id: 1,
values: {
$map: {
input: { $range: [ 0, { $size: { $arrayElemAt: [ "$values", 0 ] } } ] },
as: "index",
in: {
$reduce: {
input: "$values",
initialValue: 0,
in: { $add: [ "$$value", { $arrayElemAt: [ "$$this", "$$index" ] } ] }
}
}
}
}
}
},
{
$group: {
_id: null,
items: { $push: { $concatArrays: [ [ "$_id" ], "$values" ] } }
}
}
])
Mongo Playground
Try below aggregate pipeline
collectionName.aggregate([
{
$unwind: "$items"
},
{
$group: {
_id: {
$arrayElemAt: [
"$items",
0
]
},
sum1: {
$sum: {
$arrayElemAt: [
"$items",
1
]
}
},
sum2: {
$sum: {
$arrayElemAt: [
"$items",
2
]
}
},
sum3: {
$sum: {
$arrayElemAt: [
"$items",
3
]
}
}
}
},
{
$project: {
_id: null,
items: {
$map: {
input: {
$objectToArray: "$$ROOT"
},
as: "item",
in: "$$item.v"
}
}
}
},
{
$group: {
_id: null,
items: {
$push: "$items"
}
}
}
])
unwind the items array
group according to Tax(first position element of item using $arrayElemAt)
In project stage use map on objectToArray to get value of keys pushed into array
push the array using $group giving desired output
Output:
[
{
"_id": null,
"items": [
[
"Tax",
20,
40,
60
],
[
"FX Adjustments",
20,
40,
60
]
]
}
]
I have the collection with following data
{
"_id": "SG01",
"name": "Pawan",
"marks": [
{
"English": 93,
"Maths": 90,
"Hindi": 89,
"Sci": 98
}
],
"__v": 0
}
{
"_id": "SG02",
"name": "Dravid",
"marks": [
{
"English": 40,
"Maths": 67,
"Hindi": 56,
"Sci": 45
}
],
"__v": 0
}
{
"_id": "SG03",
"name": "Kartik",
"marks": [
{
"English": 65,
"Maths": 77,
"Hindi": 80,
"Sci": 79
}
],
"__v": 0
}
I would like to perform the operation in which marks should be displayed as total_marks of a particular student.
As I'm newbie with mongo and know how to perform basic aggregation with sum but wasn't able to understand with arrays.. However I tried but failed to get the result.
You can use below aggregation:
db.col.aggregate([
{
$unwind: "$marks"
},
{
$project: {
_id: 1,
name: 1,
marks: {
$objectToArray: "$marks"
}
}
},
{
$project: {
_id :1,
name: 1,
total_marks: {
$reduce: {
input: "$marks",
initialValue: 0,
in: { $add : ["$$value", "$$this.v"] }
}
}
}
},
{
$group: {
_id: "$_id",
name: { $first: "$name" },
total_marks: { $sum: "$total_marks" }
}
}
])
Since your marks are stored as an object you should use $objectToArray to get an array of subjects. Then you can use $reduce to sum all subjects for one student.