Exclude user in match MongoDB - mongodb

I want to add Not in query. but unfortunately I'm not getting the required result. i want to get result where user is not equal to userid. But I'm confused as to how I can add that. I tried multiple scenarios but failed.
server.get('/myFeedback', (req, res) => {
var userid = req.query.userID;
//console.log(req.query);
db.collection("tweetsWithSentimentFeedback").aggregate( [
{
$group: {
_id: {
topic: "$topic",
group : "$group",
type : "$type",
user : "$userName"
},
count: { $sum: 1 }
}
},{ $group: {
_id: {
topic: "$_id.topic",
group : "$_id.group",
},
typeAndCount: {
$addToSet: {
type: "$_id.type",
count: "$count"
}
},
userName: {
$addToSet: {
user: "$_id.userName"
}
},
totalCount: {
$sum: "$count"
}
}
},
{ $match: { $and: [ { totalCount: { $gt: 0, $lt: 15 } }, {userEqual: { $ne: [ "$userName.user", userid ] }} ] } },
// Then sort
{ "$sort": { "totalCount": -1 } }
], (err, result) => {
if (err) {
console.log(err);
}
res.status(200).send(result);
} );
});

You should add a $match as a first stage to filter the user.
{ $match: { userName: { $ne: userid } } }
Update:
db.collection("tweetsWithSentimentFeedback").aggregate(
[{
$group: {
_id: {
topic: "$topic",
group: "$group",
type: "$type",
user: "$userName"
},
count: {
$sum: 1
}
}
}, {
$group: {
_id: {
topic: "$_id.topic",
group: "$_id.group"
},
typeAndCount: {
$addToSet: {
type: "$_id.type",
count: "$count"
}
},
userName: {
$addToSet: "$_id.userName"
},
totalCount: {
$sum: "$count"
}
}
}, {
$match: {
{
totalCount: {
$gt: 0,
$lt: 15
}
},
{
userName: {
$ne: userid
}
}
}
}, , {
$sort: {
totalCount: -1
}
}])

Related

How to get this pipeline to return exactly one document?

I am running the following aggregation pipeline:
const agg = [
{
'$match': {
'aaa': 'bbb'
}
}, {
'$group': {
'_id': '',
'total': {
'$sum': '$num'
}
}
}
];
My problem is, when $match matches nothing, the pipeline returns 0 documents. How do I get the pipeline to always return 1 document?
In MongoDB version 6.0 you can do it like this one:
db.collection.aggregate([
{ $match: { aaa: 'bbb' } },
{
$group: {
_id: null,
total: { $sum: "$num" }
}
},
{
$densify: {
field: "total",
range: { step: 1, bounds: [0, 0] }
}
},
{ $set: { _id: { $cond: [{ $eq: [{ $type: "$_id" }, "missing"] }, MaxKey, "$_id"] } } },
{ $sort: { _id: 1 } },
{ $limit: 1 }
])
In version < 6.0 you can try this one:
db.collection.aggregate([
{
$facet: {
data: [
{ $match: { aaa: 'bbb' } },
{ $group: { _id: null, total: { $sum: "$num" } } }
],
default: [
{ $limit: 1 },
{ $group: { _id: null, total: { $sum: 0 } } },
{ $set: { _id: MaxKey } }
]
}
},
{ $replaceWith: { $mergeObjects: [{ $first: "$default" }, { $first: "$data" }] } },
])
Or this one:
db.collection.aggregate([
{ $match: { aaa: 'bbb' } },
{ $group: { _id: null, total: { $sum: "$num" } } },
{
$unionWith: {
coll: "collection",
pipeline: [
{ $limit: 1 },
{ $set: { _id: MaxKey, total: 0 } },
{ $project: { _id: 1, total: 1 } }
]
}
},
{ $sort: { _id: 1 } },
{ $limit: 1 }
])

Mongo DB aggregation result in the provided manner

the following data in my mongo-db
Input:
[
{
'id':1,
"year": "2022-10-01",
"Area":{
"Education":'Engineering'
}
},
{
'id':2,
"year": "2022-10-01",
"Area":{
"Education":'Commerce'
}
},
{
'id':3,
"year": "2022-10-01",
"Area":{
"Education":'Arts'
}
},
{
'id':4,
"year": "2022-10-01",
"Area":{
"Education":'Arts'
}
},
{
'id':5,
"year": "2022-01-01",
"Area":{
"Education":'Engineering'
}
},
{
'id':6,
"year": "2022-01-01",
"Area":{
"Education":'Engineering'
}
}
]
there are records of several years based on each Education field, final result to be in this form where first is grouped by date and then grouped by Education field and the count of each education field in each year
Outcome in this manner:
{
"2022-10-01": {
"Education": {
"Engineering": 1,
"Commerce": 1,
"Arts": 2
}
},
"2021-01-01": {
"Education": {
"Engineering": 2,
"Commerce": 0,
"Arts": 0
}
}
}
Try this one:
db.collection.aggregate([
{ $group: { _id: { year: "$year", Education: "$Area.Education" }, count: { $sum: 1 } } },
{ $group: { _id: "$_id.year", Education: { $push: { k: "$_id.Education", v: "$count" } } } },
{ $set: { k: "$_id", Education: { $arrayToObject: "$Education" } } },
{ $group: { _id: null, root: { $push: { k: "$_id", v: { Education: "$Education" } } } } },
{ $replaceWith: { $arrayToObject: "$root" } }
])
Mongo Playground
It is a bit difficult to count values which do not exist, because there could be infinite numbers of them. Maybe like this:
db.collection.aggregate([
{ $group: { _id: { year: "$year", Education: "$Area.Education" }, count: { $sum: 1 } } },
{ $group: { _id: "$_id.year", Education: { $push: { k: "$_id.Education", v: "$count" } } } },
{
$set: {
Education: {
$map: {
input: ["Engineering", "Arts", "Commerce"],
in: {
k: "$$this",
v: {
$let: {
vars: {
val: {
$first: {
$filter: {
input: "$Education",
as: "area",
cond: { $eq: ["$$this", "$$area.k"] }
}
}
}
},
in: { $ifNull: ["$$val.v", 0] }
}
}
}
}
}
}
},
{ $set: { k: "$_id", Education: { $arrayToObject: "$Education" } } },
{ $group: { _id: null, root: { $push: { k: "$_id", v: { Education: "$Education" } } } } },
{ $replaceWith: { $arrayToObject: "$root" } }
])

MongoDB match computed value

I've created an aggregate query but for some reason it doesn't seem to work for custom fields created in the aggregation pipeline.
return this.repository.mongo().aggregate([
{
$match: { q1_avg: { $regex: baseQuery['value'], $options: 'i' } }, // NOT WORKING
},
{
$group: {
_id: '$product_sku',
id: { $first: "$_id" },
product_name: { $first: '$product_name' },
product_category: { $first: '$product_category' },
product_sku: { $first: '$product_sku' },
q1_cnt: { $sum: 1 },
q1_votes: { $push: "$final_rating" }
},
},
{
$facet: {
pagination: [ { $count: 'total' } ],
data: [
{
$project: {
_id: 1,
id: 1,
product_name: 1,
product_category: 1,
product_sku: 1,
q1_cnt: 1,
q1_votes: {
$filter: {
input: '$q1_votes',
as: 'item',
cond: { $ne: ['$$item', null] }
}
},
},
},
{
$set: {
q1_avg: { $round: [ { $avg: '$q1_votes' }, 2 ] },
}
},
{ $unset: ['q1_votes'] },
{ $skip: skip },
{ $limit: limit },
{ $sort: sortList }
]
}
},
{ $unwind : "$pagination" },
]).next();
q1_avg value is an integer and as far as I know, regex only works with strings. Could that be the reason

Mongoose subquery

I have a collection that looks like below:
[
{
"orderNum": "100",
"createdTime": ISODate("2020-12-01T21:00:00.000Z"),
"amount": 100,
"memo": "100memo",
"list": [
1
]
},
{
"orderNum": "200",
"createdTime": ISODate("2020-12-01T21:01:00.000Z"),
"amount": 200,
"memo": "200memo",
"list": [
1,
2
]
},
{
"orderNum": "300",
"createdTime": ISODate("2020-12-01T21:02:00.000Z"),
"amount": 300,
"memo": "300memo"
},
{
"orderNum": "400",
"createdTime": ISODate("2020-12-01T21:03:00.000Z"),
"amount": 400,
"memo": "400memo"
},
]
and I'm trying to get the total amount of orders that were created before order# 300 (so order#100 and #200, total amount is 300).
Does anyone know how to get it via Mongoose?
You can use this one:
db.collection.aggregate([
{ $sort: { orderNum: 1 } }, // by default the order of documents in a collection is undetermined
{ $group: { _id: null, data: { $push: "$$ROOT" } } }, // put all documents into one document
{ $set: { data: { $slice: ["$data", { $indexOfArray: ["$data.orderNum", "300"] }] } } }, // cut desired elementes from array
{ $unwind: "$data" }, // transform back to documents
{ $replaceRoot: { newRoot: "$data" } },
{ $group: { _id: null, total_amount: { $sum: "$amount" } } } // make summary
])
Actually it is not needed to $unwind and $group, so the shortcut would be this:
db.collection.aggregate([
{ $sort: { orderNum: 1 } },
{ $group: { _id: null, data: { $push: "$$ROOT" } } },
{ $set: { data: { $slice: ["$data", { $indexOfArray: ["$data.orderNum", "300"] }] } } },
{ $project: { total_amount: { $sum: "$data.amount" } } }
])
But the answer from #turivishal is even better.
Update for additional field
{
$set: {
data: { $slice: ["$data", { $indexOfArray: ["$data.orderNum", "300"] }] },
memo: { $arrayElemAt: [ "$data.memo", { $indexOfArray: ["$data.orderNum", "300"] } ] }
}
}
or
{ $set: { data: { $slice: ["$data", { $indexOfArray: ["$data.orderNum", "300"] }] } } },
{ $set: { memo: { $last: { "$data.memo" } } },
$match orderNum less than 300
$group by null and get totalAmount using $sum of amount
YourSchemaModel.aggregate([
{ $match: { orderNum: { $lt: "300" } } },
{
$group: {
_id: null,
totalAmount: { $sum: "$amount" }
}
}
])
Playground

MongoDB get values with most recent date

I have a collection with documents such as these.
What I want to do is get all distinct clusters coming from the document with the highest (recent) lastupdate field.
I think this should be the output:
[
"19":"Income2",
"20":"Income Modified",
"21":"Income Modified"
]
Please try this :
db.yourCollection.aggregate([{ $unwind: '$meta.clusters' },
{ $project: { '_id': { $objectToArray: '$meta.clusters' }, 'last_update': 1 } }, { $sort: { 'last_update': -1 } },
{ $group: { _id: '$_id.k', values: { $first: '$$ROOT' } } }, { $sort: { 'values.last_update': -1 } },
{ $replaceRoot: { 'newRoot': '$values' } },
{ $group: { _id: '', distinctCLusters: { $push: { $arrayToObject: "$_id" } } } }, { $project: { _id: 0 } }])
Output with provided data:
{
"distinctCLusters" : [
{
"21" : "Income Modified"
},
{
"19" : "Income2"
},
{
"20" : "Income Modified"
}
]
}