mongoose match multiple ids and count if duplicate found - node.js

I have a list of ids and it may contain duplicates, so ignore duplicates and count the occurrence of total duplicates. I will explain it in details.
IDS
[
5fe10a8c4d6b0fb7f70bbf84,
5fe10a8c4d6b0fb7f70bbf84,
5ff2aad439a8602fd872ab7c
]
I have used the below code to get the result,
var user_id = [
5fe10a8c4d6b0fb7f70bbf84,
5fe10a8c4d6b0fb7f70bbf84,
5ff2aad439a8602fd872ab7c
];
User.aggregate([
{
$match: {
_id: {
$in: user_id
}
},
},
{
$group: {
_id: "$_id",
count: {
$sum: 1
}
}
},
],
(err, resp) => {
console.log(resp)
})
The output for above code is,
[
{ _id: 5ff2aad439a8602fd872ab7c, count: 1 },
{ _id: 5fe10a8c4d6b0fb7f70bbf84, count: 1 }
]
The required output is,
[
{ _id: 5ff2aad439a8602fd872ab7c, count: 1 },
{ _id: 5fe10a8c4d6b0fb7f70bbf84, count: 2 }
]
I have tried many code but no success, is there anyway to achieve required output.

you trying to get the count from _id. _id is unique for all the documents so you need to change the _id to some other fields which is not unique.
example,
table
[
{
id: 1,
values: [
1,
2,
3
]
},
{
id: 1,
values: [
1,
2,
3
]
},
{
id: 1,
values: [
1,
2,
3
]
},
{
id: 3,
values: [
1,
2,
3
]
}
]
Query
db.collection.aggregate([
{
$match: {
id: {
$in: [
1,
3
]
}
},
},
{
$group: {
_id: "$id",
count: {
$sum: 1
}
}
},
])
output
[
{
"_id": 1,
"count": 3
},
{
"_id": 3,
"count": 1
}
]

Related

Map in Mongodb with aggregation

Here is my Data in DB
{
name: abc
pro: 1
},
{
name:cde,
pro: 2
},
{
name:fgh,
pro:3
},
{
name:ijk,
pro:4
},
here is my query to aggregate the result I've successfully get the count of name and pro:
db.aggregate([
{
$facet: {
"name": [
{ $group: { _id: '$name', N: { $sum: 1 } } }
],
},{ $project: { "pro": {
$map: {
input: '$pro',
in:{ $arrayToObject: [[{ k: '$$this._id', v: '$$this.N'}]] }
}
},
}}])
For pro which is 1 in DB but against 1, I want to map a etc, in response.
Expecting Output:
{
name: abc
pro: a //value in DB is 1.
},
{
name:cde,
pro: b //value in DB is 2.
},
{
name:fgh,
pro:c //value in DB is 3
},
{
name:ijk,
pro:d //value in DB is 4
},
}
If I understand your question correctly, you need to map pro integer values to corresponding characters. Then this should work:
db.collection.aggregate([
{
$project: {
_id: 0,
name: 1,
pro: {
$slice: [
[
"",
"a",
"b",
"c",
"d"
],
"$pro",
1
]
}
}
},
{
"$unwind": "$pro"
}
])
Here is the playground link.
Use Map pro function, it will works
db.collection.aggregate([
{
$project: {
_id: 0,
name: 1,
pro: {
$slice: [
[
"",
"a",
"b",
"c",
"d"
],
"$pro",
1
]
}
}
},
{
"$unwind": "$pro"
}
])

Mongodb search field with range inside array of object

I have multiple documents in a collection like this
[
{
_id: 123,
data: 1,
details: [
{
item: "a",
day: 1
},
{
item: "a",
day: 2
},
{
item: "a",
day: 3
},
{
item: "a",
day: 4
}
],
someMoreField: "xyz"
}
]
Now I want document with _id: 123 and details field should only contain day within range of 1 to 3. So the result will be like below.
{
_id: 123,
data: 1,
details: [
{
item: 'a',
day: 1,
},
{
item: 'a',
day: 2,
},
{
item: 'a',
day: 3,
},
],
someMoreField: 'xyz',
};
I tried to do this by aggregate query as:
db.collectionaggregate([
{
$match: {
_id: id,
'details.day': { $gt: 1, $lte: 3 },
},
},
{
$project: {
_id: 1,
details: {
$filter: {
input: '$details',
as: 'value',
cond: {
$and: [
{ $gt: ['$$value.date', 1] },
{ $lt: ['$$value.date', 3] },
],
},
},
},
},
},
])
But this gives me empty result. Could someone please guide me through this?
You are very close, you just need to change the $gt to $gte and $lt to $lte.
Another minor syntax error is you're accessing $$value.date but the schema you provided does not have that field, it seems you need to change it to $$value.day, like so:
db.collection.aggregate([
{
$match: {
_id: 123,
"details.day": {
$gt: 1,
$lte: 3
}
}
},
{
$project: {
_id: 1,
details: {
$filter: {
input: "$details",
as: "value",
cond: {
$and: [
{
$gte: [
"$$value.day",
1
]
},
{
$lte: [
"$$value.day",
3
]
},
],
},
},
},
},
},
])
Mongo Playground

how to calculate total for each enum of a field in aggregate?

hello I have this function where I want to calculate the number of orders for each status in one array, the code is
let statusEnum = ["pending", "canceled", "completed"];
let userOrders = await Orders.aggregate([
{
$match: {
$or: [
{ senderId: new mongoose.Types.ObjectId(req.user._id) },
{ driverId: new mongoose.Types.ObjectId(req.user._id) },
{ reciverId: new mongoose.Types.ObjectId(req.user._id) },
],
},
},
{
$group: {
_id: null,
totalOrders: { $sum: 1 },
totalPendingOrders: "??", //I want to determine this for each order status
totalCompletedOrders: "??",
totalCanceledOrders: "??",
},
},
]);
so I could add add a $match and use {status : "pending"} but this will filter only the pending orders, I could also map the status enum and replace each element instead of the "pending" above and then push each iteration in another array , but that just seems so messy, is there any other way to calculate total for each order status with using only one aggregate?
thanks
You can use group as you used, but with condition
db.collection.aggregate([
{
$group: {
_id: null,
totalPendingOrders: {
$sum: { $cond: [ { $eq: [ "$status", "pending" ] }, 1, 0 ] }
},
totalCompletedOrders: {
$sum: { $cond: [ { $eq: [ "$status", "completed" ] }, 1, 0 ] }
},
totalCanceledOrders: {
$sum: { $cond: [ { $eq: [ "$status", "canceled" ] }, 1, 0 ] }
}
}
}
])
Working Mongo playground

How to shift element from one array position to another in MongoDB with mongoose?

I have got an array of objects in MongoDB and I was moving a particular element id (i.e 1) from its position to below element having id (i.e 2). So that we can get element with id as 2 -> 1 -> 3.
const arr = [
{
id: 1,
name: 'foo'
},
{
id: 2,
name: 'bar'
},
{
id: 3,
name: 'zoo'
}
]
What I've done is used $pull and $push but it gives ConflictingUpdateOperators and I don't know how to deal with it.
updatedPlan = await Plan.findOneAndUpdate(
{ _id: req.params.id },
{
$pull: {
"arr": {
id: 1
}
},
$push: {
"arr" : {
$each: [{ id: 1, name: 'foo'}],
$position: 1
}
},
);
In MongoDB 4.2 or newer you can update a document with Aggregation Pipeline. Using simple $map on a $range of array indexes you can shuffle these indexes and use $arrayElemAt in order to build a new array:
db.col.update({ _id: req.params.id }, [
{
$set: {
arr: {
$map: {
input: { $range: [ 0, { $size: "$arr" } ] },
in: {
$let: {
vars: {
newIndex: {
$switch: {
branches: [
{ case: { "$eq": [ "$$this", 0 ] }, then: 1 },
{ case: { "$lte": [ "$$this", 1 ] }, then: { $subtract: [ "$$this", 1 ] } },
],
default: "$$this"
}
}
},
in: {
$arrayElemAt: [ "$arr", "$$newIndex" ]
}
}
}
}
}
}
}
])

how to fetch seller order from multiple collection data

I have 4 collections for store order data.
1. order => field => _id, order_no, cust_id, order_date
2. order_address => field => _id, order_id, cust_name, mobile, address
3. order_details => field => _id, order_id, product_id, seller_id, qty, price
4. order_payment => field => _id, payment_type, payment_status
in that order_details collection has n number of record for a number of product in one order.
in that how to get particular seller order from my data using aggregate in node.js from MongoDB database
i try this code but it's show ordre_details = [] but show order in my result:
var query = [
{ "$lookup": {
from: 'order_details',
let: { order_id: "$_id" },
pipeline: [
{ $match: { $expr: { $and: [{ $eq: [ "$order_id", "$$order_id" ] }, { $eq: [ "$seller_id", ObjectID(seller_id) ] }] } } },
{ $project: {
amount: 1,
cod_charge: 1,
shipping_charge: 1,
pid: 1,
product_attribute_id: 1,
qty: 1
} },
{ "$lookup": {
from: 'product',
let: { product_id: "$pid", product_attribute_id: '$product_attribute_id'},
pipeline: [
{ $match: { $expr: { $eq: [ "$_id", "$$product_id" ] } } },
{ $project: { _id: 1, name: 1, sku: 1 } },
{ "$lookup": {
from: 'product_image',
let: { product_attribute_id: '$$product_attribute_id' },
pipeline: [
{ $match: { $expr: { $eq: [ "$product_attribute_id", "$$product_attribute_id" ] } } },
{ $project: { _id: 0, image: 1, is_default: 1 } },
{ $sort : { is_default: -1 } },
{ $replaceRoot: { newRoot: {_id: "$_id", image: "$image" } } }
],
as: 'product_image'
} },
{ $replaceRoot: { newRoot: {
_id: "$_id",
name: "$name",
sku: "$sku",
image: { $arrayElemAt: [ "$product_image.image", 0 ] }
} } }
],
as: 'product'
} },
{ "$replaceRoot": { newRoot: {
_id: '$$ROOT._id',
pid: '$$ROOT.pid',
amount: '$$ROOT.amount',
cod_charge: '$$ROOT.cod_charge',
shipping_charge: '$$ROOT.shipping_charge',
product_attribute_id: "$$ROOT.product_attribute_id",
qty: "$$ROOT.qty",
product: { $arrayElemAt: [ "$product", 0 ] },
} } },
],
as: 'order_details'
} },
{ "$replaceRoot": {
newRoot: {
_id: "$_id",
order_no: "$order_no",
cust_id: "$cust_id",
order_date: "$order_date",
order_details: "$order_details"
}
} }
]
orderModel.order.aggregate(query, function(err, orderData){})

Resources