how to use aggreate query using in mongodb? - node.js

I have the following documents in my collection. Need to get all employees in stores using the aggregate function.
//Store 1
{
"_id" : ObjectId("5b0d3fa6b426ea12ec0f6e5a"),
"store_name": KFC
"employees":[
ObjectId("5b0d4c5ec47e6223a08af5fd"), //query id
ObjectId("5b3b0ea9074f944699f1bcfc"),
ObjectId("5b11558d0a50c067a91875e9"),
],.. },
//Store 2
{
"_id" : ObjectId("5b0d3fa6b426ea12ec0f6e5a"),
"store_name": McDonalds
"employees":[
ObjectId("5b0d4c5ec47e6223a08af5fd"),
ObjectId("5b3b0ea9074f944699f1bcfc"),
ObjectId("5b11558d0a50c067a91875e9"),
],.. },
//Store 3
{
"_id" : ObjectId("5b0d3fa6b426ea12ec0f6e5a"),
"store_name": Dominos
"employees":[
ObjectId("5b0d4c5ec47e6223a08af5fd"),
ObjectId("5b1623905bc92d76abfe0ab1"),
ObjectId("5b14e0b1fc1507569f830f7d")
],.. }
Using aggregate function
db.getCollection('stores').aggregate([
{
$match:{
"employees":{
$in:[ ObjectId("5b0d4c5ec47e6223a08af5fd")] //employee_id
}
}
},{
$unwind: "$employees"
},{
$group: {
"_id": null,
"emps": {
$addToSet: "$employees"
}
}
}
])
OUTPUT
{
"_id" : null,
"emps" : [
ObjectId("5b0d4c5ec47e6223a08af5fd"), // employee id
ObjectId("5b3b0ea9074f944699f1bcfc"),
ObjectId("5b11558d0a50c067a91875e9"),
ObjectId("5b1623905bc92d76abfe0ab1"),
ObjectId("5b14e0b1fc1507569f830f7d")
]
}
its fine. I need to get this result without the employee queried id. how i handle it.
Here, How can I remove the queried employee id & need to get result like this
{
"_id" : null,
"emps" : [
ObjectId("5b3b0ea9074f944699f1bcfc"),
ObjectId("5b11558d0a50c067a91875e9"),
ObjectId("5b1623905bc92d76abfe0ab1"),
ObjectId("5b14e0b1fc1507569f830f7d")
]
}

You can use $filter and repeat your $in condition insinde $not:
db.getCollection('stores').aggregate([
// your pipeline,
{
$addFields: {
emps: {
$filter: {
input: "$emps",
as: "emp",
cond: { $not: { $in: [ "$$emp", [ ObjectId("5b0d4c5ec47e6223a08af5fd")] ] } }
}
}
}
}
])
$addFields is used to replace existing emp field

Related

Searching in nested arrays Mongodb

I have a mongodb with some JSON data which includes and nested arrays. I am
trying to make a query to count how many documents have a specific
value. For example here is how my json data looks:
{
"_id" : ObjectId("5ecb815bf4b8512918224e71"),
"array1" : [
{
"_id" : ObjectId("5ecb815bf4b8512918224e85"),
"xxxx" : "1450",
"yyyy" : 83,
"array2" : [
{
"_id" : ObjectId("5ecb815bf4b8512918224e88"),
"aaaa" : "1470420945276",
},
{...},
{...}]
}
The query that i am trying is the following:
db.example.aggregate([
{
$project: {
value1: {
$filter: {
input: "$array1",
as: "array",
cond: { $eq: [ "$$array.array2.aaaa" , "1470420945276" ] }
}
}
}
},
{
$project: {
value1Count: { $size: "$value1" }
}
}
])
But doesnt work and returns that value1Count=0. It looks like it doesnt nnavigate into the array2 to
read the value of the 'aaaa'. Any help?
You were almost close to getting the desired value. The problem is $$array.array2.aaaa returns an array value, so we can't use $eq here. Instead, we should use $in operator.
db.example.aggregate([
{
$project: {
value1: {
$filter: {
input: "$array1",
as: "array",
cond: {
$in: [
"1470420945276",
"$$array.array2.aaaa"
]
}
}
}
}
},
{
$project: {
value1Count: {
$size: "$value1"
}
}
}
])
MongoPlayground | Alternative solution

MongoDB find documents which have multiple keys in a field

This is how a documents looks like in my dataset:
{
username: 'stack',
attempts: { 1517761701: false, 1512341532: true }
}
{
username: 'overflow',
attempts: { 1217563721: false }
}
Now, I want to retrieve every document in my dataset where attempts contains more than óne key. So the query should return the document of user 'stack' but not of user 'overflow'. What query can I apply here?
try $objectToArray to convert object to array and count the number of keys if you are using mongo 3.6+
db.cols.aggregate(
[
{$addFields: {count : {$size : {$ifNull : [{$objectToArray : "$attempts"}, []]}}}},
{$match: {count : {$gt : 1}}},
{$project: {count : 0}}
]
)
Use $redact for a single pipeline:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$gt": [
{ "$size": {
"$objectToArray": {
"$ifNull": [
"$attempts",
{ }
]
}
} },
1
]
},
"$$KEEP",
"$$PRUNE"
]
}
}
])
Convert attempts to an array, $unwind and then use $sortByCount to do all the work..
db.collection_name.aggregate( [
{ $addFields : { array : { $objectToArray : "$attempts"} } },
{ $unwind : "$array" },
{ $sortByCount : "$username" },
{ $match : { count : { $gte : 2 } } }
])
Outputs:
{
"_id" : "stack",
"count" : 2
}

Use $addToSet (aggregate) to add objects to an array with one or more distinct properties

function findProfilesBySteamIds(ids, res) {
var match = {
$match: {
$and : [
{ steamid: { $in : ids } }
]
}
}
var sort = {
$sort: {
createdAt : -1
}
}
var group = {
$group: {
_id : "$steamid",
profile : { $first : "$$ROOT" },
personahistory : { $push : "$$ROOT" }
}
}
SteamUser
.aggregate([match, sort, group])
}
Okay so here is my issue. I have a collection of profiles with a unique identifier steamid. I am grouping by $steamid and that functionality is working as expected. I also want to add a new field (not in the Schema) called personahistory that has an array of objects that is DISTINCT based on another property of the document, called personaname.
I have tried to use $addToSet following the mongoose reference docs but so far can only use it to create an array of that property only:
$group: {
_id : "$steamid",
profile : { $first : "$$ROOT" },
personahistory : { $addToSet : "$personaname" }
}
This outputs:
{
"_id": "1234567890",
"profile": { ... },
"personahistory" : [
"personaname1",
"personaname2",
"personaname3"
]
}
Instead I'd like the output to be along the lines of:
{
"_id": "1234567890",
"profile": { ... },
"personahistory" : [
{
"_id": "1234567890",
"personaname": "personaname1",
...
},
{
"_id": "1234567891",
"personaname": "personaname2",
...
},
{
"_id": "1234567892",
"personaname": "personaname3",
...
}
]
}
I've tried something like:
{
$addToSet : {
"_id": "$steamid",
"personaname": "$personaname"
}
}
but to no avail.
Furthermore, if this behavior is even possible, I'd like to be able to use two or more DISTINCT fields. So, get all unique combinations of personaname and avatarurl and add those to the set.
Basically, I have a record each time the profile is queried but I only want to return records that are unique based on those two fields.
I'll be happy to provide more information if I haven't been clear enough.

Search for most common "data" with mongoose, mongodb

My structure.
User:
{
name: "One",
favoriteWorkouts: [ids of workouts],
workouts: [ { name: "My workout 1" },...]
}
I want to get list of favorits/hottest workouts from database.
db.users.aggregate(
{ $unwind : "$favorite" },
{ $group : { _id : "$favorite" , number : { $sum : 1 } } },
{ $sort : { number : -1 } }
)
This returns
{
"hot": [
{
"_id": "521f6c27145c5d515f000006",
"number": 1
},
{
"_id": "521f6c2f145c5d515f000007",
"number": 1
},...
]}
But I want
{
hot: [
{object of hottest workout 1, object of hottest workout 2,...}
]}
How do you sort hottest data and fill the result with object, not just ids?
You are correct to want to use MongoDB's aggregation framework. Aggregation will give you the output you are looking for if used correctly. If you are looking for just a list of the _id's of all users' favorite workouts, then I believe that you would need to add an additional $group operation to your pipeline:
db.users.aggregate(
{ $unwind : "$favoriteWorkouts" },
{ $group : { _id : "$favoriteWorkouts", number : { $sum : 1 } } },
{ $sort : { number : -1 } },
{ $group : { _id : "oneDocumentWithWorkoutArray", hot : { $push : "$_id" } } }
)
This will yield a document of the following form, with the workout ids listed by popularity:
{
"_id" : "oneDocumentWithWorkoutArray",
"hot" : [
"workout6",
"workout1",
"workout5",
"workout4",
"workout3",
"workout2"
]
}

How to build query for relating parent document's field to embedded array document's field. Using MongoDB aggregation Operators

Consider the following document in the collection named 'CityAssociation'
{
"_id" : "MY_ID",
"ThisCityID" : "001",
"CityIDs" : [{
"CityID" : "001",
"CityName" : "Bangalore"
}, {
"CityID" : "002",
"CityName" : "Mysore"
}],
"CityUserDetails": {
"User" : "ABCD"
}
}
Now I have User value i.e. in above case I have value ABCD and want to find it with only city where the first level's field ThisCityID matches to the embedded array documnet's field CityID. Finally I need to project as follows (for the above case):
{
'UserName': 'ABCD',
'HomeTown':'Bangalore'
}
In Node.js + MongoDB native drive, I wrote a aggregation query as follows which is not working as expected.
collection.aggregate([
{ $match: { 'CityUserDetails.User': 'ABCD', 'CityIDs': { $elemMatch: { CityID: ThisCityID}}} },
{ $unwind: "$CityIDs" },
{ $group: {
_id: '$_id',
CityUserDetails: { $first: "$CityUserDetails" },
CityIDs: { $first: "$CityIDs" }
}
},
{ $project: {
_id: 0,
"UserName": "$CityUserDetails.User",
"HomeTown": "$CityIDs.CityName"
}
}
], function (err, doc) {
if (err) return console.error(err);
console.dir(doc);
}
);
Can anyone tell me how this can be done with query.
Note: On MongoDB schema we don't have control to change it.
You can use the $eq operator to check if the first level's field ThisCityID matches embedded array document's field CityID.
db.city.aggregate([
{ $match : { "CityUserDetails.User" : "ABCD" }},
{ $unwind : "$CityIDs" },
{ $project : {
matches : { $eq: ["$CityIDs.CityID","$ThisCityID"]},
UserName : "$CityUserDetails.User",
HomeTown : "$CityIDs.CityName"
}},
{ $match : { matches : true }},
{ $project : {
_id : 0,
UserName : 1,
HomeTown : 1
}},
])
And the result is:
{
"result" : [
{
"UserName" : "ABCD",
"HomeTown" : "Bangalore"
}
],
"ok" : 1
}

Resources