mongodb get distinct values with category - mongodb

Suppose there is the following collection
People:
{
_id: 1,
name: 'john',
last_name: 'blah1',
job: 'lifeguard'
}
{
_id: 2,
name: 'john',
last_name: 'blah2',
job: 'lifeguard'
}
{
_id: 3,
name: 'alex',
last_name: 'blah3',
job: 'lifeguard'
}
{
_id: 4,
name: 'alex',
last_name: 'blah4',
job: 'lifeguard'
}
{
_id: 5,
name: 'alex',
last_name: 'blah5',
job: 'gardener'
}
I need to get the distict jobs with an array of distict names:
Trying to get the following result:
[
{
value: 'lifeguard',
names: [
'john',
'alex'
],
},
{
value: 'gardener',
names: [
'alex'
],
},
]
I understand how to get the unique jobs
db.people.find().distinct('jobs')
However i did not figure out how to do a distinct query with multiple properties.

Better to use the aggregation framework where you have a pipeline that has a $group stage to group the documents by the job key and then construct the names distinct array within the group by the accumulator $addToSet.
Consider the following aggregate operation:
db.people.aggregate([
{
"$group": {
"_id": "$job",
"names": { "$addToSet": "$name" }
}
}
])

#chridam did help me find the right answer, in the real world my object was more like
{
_id: 1,
name: ['john', 'bah1', 'blah2', 'blah3'],
last_name: 'blah1',
job: 'lifeguard'
}
so i had to $unwind the names and aggregate $group just like in #chridam's answer.
model.aggregate([
{$unwind: "$name"},
{
$group: {
_id:"$name",
jobs: {
$addToSet: "$job"
}
}
}
]

Related

MongoDB Select documents by the value of a specific field

MongoDB - userModel (simplified)
{
_id: "exampleid1",
name: "examplename1",
following: [
{
_id: "exampleid2",
name: "examplename2"
},
{
_id: "exampleid3",
name: "examplename3"
}
],
followers: [
{
_id: "exampleid4",
name: "examplename4"
},
{
_id: "exampleid5",
name: "examplename5"
}
]
}
Hey,
I'm building a social media platform and I need to get from the database only the users that I follow.
I tried the query below, but gives me nothing:
User.find( { "followers": { _id: "exampleid1"} } )
Try to divide the document selection ({_id: "exampleid1"}) from the projection ({followers: 1, _id: 0}):
db.collection.find({
_id: "exampleid1"
},
{
followers: 1,
_id: 0
})
See how it works on the playground example

Extract list of data from collections

I have a list of collection like the following in mongodb
{ _id: ObjectId("6087feeef467a4320883daf3"),
name: 'group 1',
admins: ['adam', 'ken']
}
{ _id: ObjectId("2087feeef467a4320883daf3"),
name: 'group 2',
admins: ['rebecca']
}
{ _id: ObjectId("9987feeef467a4320883daf3"),
name: 'group 3',
admins: []
}
I need to extract out all the admins, the end result would be something like this:
[
'admin',
'ken',
'rebecca'
]
How can i do that, i stuck at this part:
db.data.find({ admins: { $exists: true, $not: {$size: 0} } })
This will show all collections, but i just need the list
The proper way of doing so using single query is unwinding the array of admins and adding them to a new set.
db.collection.aggregate([
{
$unwind: "$admins"
},
{
$group: {
_id: null,
adminsSet: {
$addToSet: "$admins"
}
}
}
])
The end result will be the following so you could extract your flattened array:
[
{
"_id": null,
"adminsSet": [
"ken",
"rebecca",
"adam"
]
}
]
Mongo playground ref: https://mongoplayground.net/p/LFYsqHdTucN
You can do something like this
db.data.aggregate([
{$unwind: "$admins"},
{$project:{_id:0}}
]).map(x => x.admins);
Result
[
"adam",
"ken",
"rebecca"
]

Merge records if one field matches, but not if another field has values in both records MongoDb aggregation

I have some records like :
{
id: 1,
phone: "+15555555555",
name: "Acme CO.",
vendorcode: "ACMEC"
},
{
id: 2,
phone: "+15555555555",
name: "Acme corporation company",
vendorcode: "ACMECOMPANY"
},
{
id: 3,
phone: "+15555555555",
name: "Acme Incorporated",
vendorcode: null
}
I want to merge records:
IF phone field matches, merge the records. (can overwrite values with the values of the next record being merged).
But if there are vendorcode non-null values in multiple records, create an arrray of values. So "vendorcode" in the new record would be an array.
I would like the output of the above collection to be something like:
{
phone: "+15555555555",
name: "Acme Co.",
vendorcode: ["ACMEC","ACMECOMPANY"]
}
in a new collection.
How to write an aggregation for this in mongodb?
$group by phone, select first name, phone
$ifNull will return vendorcode if its not null
$addToSet to make array of unique vendorcode
$project to remove _id field
$out to write query result in new collection, this will create a new collection and write this query result
db.collection.aggregate([
{
$group: {
_id: "$phone",
phone: { $first: "$phone" },
name: { $first: "$name" },
vendorcode: {
$addToSet: { $ifNull: ["$vendorcode", "$$REMOVE"] }
}
}
},
{ $project: { _id: 0 } },
{ $out: "newCollectionName" }
])
Playground

MongoDB: Use $lookup aggregation in countDocuments()

I am trying to make a pagination and would like to use the mongoDB's countDocuments() method to return the total number of teams who's leader belongs to DC organization.
teams collection:
{
_id: 1,
name: 'avengers',
leader_id: 'L1'
},
{
_id: 2,
name: 'justice league',
leader_id: 'L2'
},
{
_id: 3,
name: 'suicide squad',
leader_id: 'L3'
}
leaders collection:
{
_id: 'L1',
name: 'ironman',
organization: 'MCU'
},
{
_id: 'L2',
name: 'superman',
organization: 'DC'
},
{
_id: 'L3',
name: 'harley quinn',
organization: 'DC'
}
My question is, can we use the $lookup aggregation as the query to match my output?
No, countDocuments does not take aggregation operators in its argument. You can use the $count stage to get the count of documents in the pipeline.

How do you write a query that takes into account multiple numbers and orders them

My data looks something like this:
{_id: ObjectId("5e10c2d61a9201e439335816"), name: "Bob", redWins: 23, blueWins: 34}
{_id: ObjectId("5e10c34e1a9201e439335818"), name: "Alice", redWins: 41, blueWins: 52}
{_id: ObjectId("5e10c36f1a9201e439335819"), name: "John", redWins: 12, blueWins: 24}
The goal is to be able to sort the data from most to least total wins (redWins + blueWins) and have a result that has the name and the amount of total wins in it. Desired output:
{name: "Alice", totalWins: 93},
{name: "Bob", totalWins: 57},
{name: "John", totalWins: 36}
One of the things I tried to use aggregation but I can't seem to figure out how to add the numbers before sorting them.
Thanks!
Use $addFields with $sum.
db.collection.aggregate([
{
$addFields: {
totalWins: {$sum: ["$redWins", "$blueWins"]}
}
},
{
$sort: {
totalWins: -1
}
},
{
$project: {
name: 1,
totalWins: 1,
_id: 0
}
}
])