How to find most common value for specific categories in MongoDB? - mongodb

I have a dataset in MongoDB that looks like this:
{ "name": "Tom's", "category": "coffee shop" },
{ "name": "Red Lobster", "category": "restaurant" },
{ "name": "Tom's", "category": "coffee shop" },
{ "name": "Starbucks", "category": "coffee shop" },
{ "name": "Central Park", "category": "park" },
{ "name": "Office", "category": "office" },
{ "name": "Red Lobster", "category": "restaurant" },
{ "name": "Home", "category": "home" },
{ ... } // and so on
How can I find the most common value for specific categories? For example, the most common occurring value for coffee shop and restaurant should be Tom's and Red Lobster, respectively.
My current $aggregate query only seems to list the most common occurring value among ALL of the dataset:
db.collection.aggregate(
{ "$group": { "_id": { "name": "$name" }, "count": { "$sum":1 } }},
{ "$group": { "_id": "$_id.name", "count": { "$sum": "$count" } }},
{ "$sort": { "count":-1 }}
)

You can try the below query.
$group on category and name to get the count for each category and name combination.
$sort the input documents by category and count desc.
$group on category with $first to pick the document with most occurrences.
db.collection_name.aggregate([
{
"$group": {
"_id": {
"category": "$category",
"name": "$name"
},
"count": {
"$sum": 1
}
}
},
{
"$sort": {
"_id.category": 1,
"count": -1
}
},
{
"$group": {
"_id": {
"category": "$_id.category"
},
"name": {
"$first": "$_id.name"
},
"count": {
"$first": "$count"
}
}
}
])

Related

Find last inserted document for a given field

Using Go driver for Mongo, I have a simple collection, each document is my last visit to the city. How to find all documents, most recent visit to field destination.
Field _id is auto-generated and incrementing chronologically.
[
{
"_id": "62e0d290fd1a769bb8ad13ba",
"destination": "NY"
"airline": "Delta"
},
{
"_id": "62e0d2defd1a769bb8ad13bb",
"destination": "DC"
"airline": "Southwest"
},
{
"_id": "62e0d2defd1a769bb8ad13bc",
"destination": "DC"
"airline": "American"
{
"_id": "62e0d2defd1a769bb8ad13bd",
"destination": "NY"
"airline": "JetBlue"
}
]
Expected output (most recent inserted document for visit to each city)
[
{
"_id": "62e0d2defd1a769bb8ad13bc",
"destination": "DC"
"airline": "American"
{
"_id": "62e0d2defd1a769bb8ad13bd",
"destination": "NY"
"airline": "JetBlue"
}
]
Hope this answer will help to you
db.collection.aggregate([
{
"$group": {
"_id": "$destination",
"airline": {
"$last": "$airline"
},
"destination": {
"$last": "$destination"
},
"id": {
"$last": "$_id"
}
}
},
{
"$project": {
_id: "$id",
destination: 1,
airline: 1
}
},
{
"$sort": {
_id: 1,
}
}
])

Sorting on top of grouping in mongodb

I have list of subjects as follows:
[
{ "name": "Algorithms", "category": "Computer Science" },
{ "name": "Android Programming", "category": "Computer Science" },
{ "name": "Polish", "category": "Foreign Languages" },
{ "name": "Portuguese", "category": "Foreign Languages" },
{ "name": "Quechua", "category": "Foreign Languages" },
{ "name": "Health and Medicine", "category": "Science" },
{ "name": "Inorganic Chemistry", "category": "Science" }
]
I am trying to group this based on the category as follows:
[
{
"_id": "Computer Science",
"subjects": [
{
"id": "5d2dfd5e349a9a3a48e538ce",
"name": "Algorithms"
},
{
"id": "5d2dfd5e349a9a3a48e538cf",
"name": "Android Programming"
}
],
"count": 2
},
{
"_id": "Foreign Languages",
"subjects": [
{
"id": "5d2dfd5e349a9a3a48e538d0",
"name": "Polish"
},
{
"id": "5d2dfd5e349a9a3a48e538d1",
"name": "Portuguese"
},
{
"id": "5d2dfd5e349a9a3a48e538d2",
"name": "Quechua"
}
],
"count": 3
},
{
"_id": "Science",
"subjects": [
{
"id": "5d2dfd5e349a9a3a48e538d3",
"name": "Health and Medicine"
},
{
"id": "5d2dfd5e349a9a3a48e538d4",
"name": "Inorganic Chemistry"
}
],
"count": 2
}
]
I also want the categories to be sorted and subjects to be sorted in each category.
This is what I have done so far:
db.coll.aggregate(
{
$group: {
_id: "$category",
subjects: {
$push: {
id: "$_id",
name: "$name"
}
},
count: { $sum: 1 }
}
});
The above works fine in terms of grouping the subjects by categories. But I am not able to do the sorting on top of grouping. I want to sort the categories as well as the subjects in each category.
Run $sort on name before you apply $group and then run next $sort by _id after $group:
db.col.aggregate([
{ $sort: { name: 1 } },
{
$group: {
_id: "$category",
subjects: {
$push: {
id: "$_id",
name: "$name"
}
},
count: { $sum: 1 }
}
},
{ $sort: { _id: 1 } }
]);
Mongo Playground

Need to return matched data from mongo db JSON

I have Json which have values like state_city details this contains information like which city belongs to which state -
Need to query it for particular state name which will gives me all cities that belongs to that state.
db.collection.find({
"count": 10,
"state.name": "MP"
})
[
{
"collection": "collection1",
"count": 10,
"state": [
{
"name": "MH",
"city": "Mumbai"
},
{
"name": "MH",
"city": "Pune"
},
{
"name": "UP",
"city": "Kanpur"
},
{
"name": "CG",
"city": "Raipur"
}
]
},
{
"collection": "collection2",
"count": 20,
"state": [
{
"name": "MP",
"city": "Indore"
},
{
"name": "MH",
"city": "Bhopal"
},
{
"name": "UP",
"city": "Kanpur"
},
{
"name": "CG",
"city": "Raipur"
}
]
}
]
You have to use aggregate query to get only matching elements in array :
db.collection.aggregate([{
$unwind: "$content.state"
},
{
$match: {
"content.state.name": "MH",
"count": 10
}
},
{
$group: {
_id: "$content.state.city",
}
},
{
$addFields: {
key: 1
}
},
{
$group: {
_id: "$key",
cities: {
$push: "$_id"
}
}
},
{
$project: {
_id: 0,
cities: 1
}
}
])
This query will return :
{
"cities": [
"Pune",
"Mumbai"
]
}
The following query would be the solution.
db.collection.find({ "count": 10, "state":{"name": "MP"}})
For more complex queries, $elemMatch is also available.

Filter nested array in mongodb? [duplicate]

This question already has answers here:
Find in Double Nested Array MongoDB
(2 answers)
Closed 4 years ago.
I have a document that looks like so:
{
"_id": {
"$oid": "5b1586ccf0c56353e89d330b"
},
"address": {
"street": "123 Street",
"address2": "Address 2",
"city": "Some City",
"state": "MI",
"zip": "12345"
},
"subs": [
{
"invoices": [
{
"address": {
"street": "3061 Pine Ave SW",
"city": "Grandville",
"state": "AK",
"zip": "49418"
},
"lineItem": [
{
"images": [
{
"_id": {
"$oid": "5b1fca54e6ee1d80c463612d"
},
"name": "1528810066348_RSA Logo.jpeg",
"url": "https....",
"uploadDate": {
"$date": "2018-06-12T13:27:46.931Z"
},
"size": 91819
}
],
"_id": {
"$oid": "5b1fca54e6ee1d80c463612c"
},
"desc": "2",
"amt": 2
}
],
"_id": {
"$oid": "5b1fca54e6ee1d80c463612b"
}
}
],
"_id": {
"$oid": "5b1fc7f23b595481d4599f58"
},
"email": "a#a.com",
"scope": "Roof",
},
{
"invoices": [
{
"address": {
"street": "3061 Pine Ave SW",
"city": "Grandville",
"state": "AL",
"zip": "49418"
},
"lineItem": [
{
"images": [
{
"_id": {
"$oid": "5b1fca2fe6ee1d80c463612a"
},
"name": "1528810029700_RSA Stamp.png",
"url": "https....",
"uploadDate": {
"$date": "2018-06-12T13:27:10.403Z"
},
"size": 238113
}
],
"_id": {
"$oid": "5b1fca2fe6ee1d80c4636129"
},
"desc": "1",
"amt": 1
}
],
"_id": {
"$oid": "5b1fca2fe6ee1d80c4636128"
}
},
{
"address": {
"street": "3061 Pine Ave SW",
"city": "Grandville",
"state": "AL",
"zip": "49418"
},
"lineItem": [
{
"images": [
{
"_id": {
"$oid": "5b1fd05b0d1f7185e02e9c40"
},
"name": "1528811607099_error page.PNG",
"url": "https....",
"uploadDate": {
"$date": "2018-06-12T13:53:28.080Z"
},
"size": 224772
}
],
"_id": {
"$oid": "5b1fd05b0d1f7185e02e9c3f"
},
"desc": "3",
"amt": 3
}
],
"_id": {
"$oid": "5b1fd05b0d1f7185e02e9c3e"
}
}
],
"_id": {
"$oid": "5b1fc7f23b595481d4599f55"
},
"email": "b#b.com",
"scope": "Siding",
}
],
"firstName": "",
"lastName": "",
}
My issue is that I want to be able to access a specific invoices of a specific subs.
I am new to Mongo/Mongoose so it is possible I am doing something completely wrong and I would be more than happy with any answer/criticism on how I am approaching this.
-- tweaked answer --
Job.aggregate([
{
$match: {
"_id": mongoose.Types.ObjectId(req.body.jobID)
}
},
{
$unwind: "$subs"
},
{
$match: {
"subs._id": mongoose.Types.ObjectId(req.body.subID)
}
},
{
$unwind: "$subs.invoices"
},
{
$match: {
"subs.invoices._id": mongoose.Types.ObjectId(req.body.invID)
}
},
{
$project: {
"_id": 1,
"subs.invoices": 1
}
}
], function(err, job) {
if (err) throw err;
res.send(job);
});
You can try below aggregation...
Here this is a long process of deconstructing an array using $unwind and rebuild the array using $group
db.collection.aggregate([
{ "$match": { "_id": "1111" } },
{ "$unwind": "$subs" },
{ "$match": { "subs._id": "2222" } },
{ "$unwind": "$subs.invoices" },
{ "$match": { "subs.invoices._id": "3333" } },
{ "$group": {
"_id": {
"_id": "$_id",
"subs": "$subs._id"
},
"firstName": { "$first": "$firstName" },
"lastName": { "$first": "$lastName" },
"address": { "$first": "$address" },
"subs": {
"$first": {
"_id": "$subs._id",
"email": "$subs.email",
"venue": "$subs.venue",
"scope": "$subs.scope"
}
},
"invoices": { "$push": "$subs.invoices" }
}},
{ "$group": {
"_id": "$_id._id",
"firstName": { "$first": "$firstName" },
"lastName": { "$first": "$lastName" },
"address": { "$first": "$address" },
"subs": {
"$push": {
"_id": "$subs._id",
"email": "$subs.email",
"venue": "$subs.venue",
"scope": "$subs.scope",
"invoices": "$invoices"
}
}
}}
])
Or you can do this with $filter aggregation as well
db.collection.aggregate([
{ "$match": { "_id": "5b1586ccf0c56353e89d330b" }},
{ "$unwind": "$subs" },
{ "$match": { "subs._id": "5b1fc7f23b595481d4599f58" }},
{ "$project": {
"address": 1, "firstName": 1, "lastName": 1,
"subs.type": "$subs._id",
"subs.status": "$subs.email",
"subs.code": "$subs.scope",
"subs.invoices": {
"$filter": {
"input": "$subs.invoices",
"as": "invoice",
"cond": {
"$eq": [
"$$invoice._id",
"5b1fca54e6ee1d80c463612b"
]
}
}
}
}},
{ "$group": {
"_id": "$_id",
"address": { "$first": "$address" },
"firstName": { "$first": "$firstName" },
"lastName": { "$first": "$lastName" },
"subs": { "$push": "$subs" }
}}
])

sort a pushed array in mongodb

I have a mongodb result like this.
[
{
"_id": {
"_id": "57174838afb8eb97ccd409ca",
"name": "Yet another position",
"description": "description",
"code": "11Y-WK"
},
"votes": [
{
"candidate": {
"_id": "56f19694e84a6bf1b66ad378",
"surname": "XXXXXXXXX",
"firstName": "XXXXXXXXX",
"middleName": "XXXXXXXXX",
"othername": " XXXXXXXXX XXXXXXXXX",
"sc_number": "071050"
},
"count": 3
},
{
"candidate": {
"_id": "56f19690e84a6bf1b66aa558",
"surname": "XXXXXXXXX",
"othername": "XXXXXXXXX XXXXXXXXX",
"sc_number": "034837"
},
"count": 2
},
{
"candidate": {
"_id": "56f19690e84a6bf1b66aa2f3",
"surname": "XXXXXXXXX",
"othername": "XXXXXXXXX XXXXXXXXX",
"sc_number": "008243"
},
"count": 4
}
],
"total_count": 9
},
{
"_id": {
"_id": "571747a8afb8eb97ccd409c7",
"name": "Test Position",
"description": "Description",
"code": "10T-9K"
},
"votes": [
{
"candidate": {
"_id": "56f19690e84a6bf1b66aa3b7",
"surname": "XXXXXXXXX",
"othername": "XXXXXXXXX",
"sc_number": "044660"
},
"count": 1
},
{
"candidate": {
"_id": "56f19690e84a6bf1b66aa6ea",
"surname": "XXXXXXXXX",
"othername": "XXXXXXXXX",
"sc_number": "062444"
},
"count": 5
},
{
"candidate": {
"_id": "56f1968fe84a6bf1b66aa03e",
"surname": "XXXXXXXXX",
"othername": "XXXXXXXXX",
"sc_number": "042357"
},
"count": 3
}
],
"total_count": 9
}
]
I need to sort by count in descending order.
Below is the query that returns the result above.
I've tried applying sort at all stages but with no luck.
Vote.aggregate([
{ "$match": { "_poll" : mongoose.mongo.ObjectID(req.query._poll) } },
{
"$group": {
"_id": {
"_position": '$_position',
"candidate": '$candidate'
},
"voteCount": { "$sum": 1 }
}
},
{
"$group": {
"_id": "$_id._position",
"votes": {
"$push": {
"candidate": "$_id.candidate",
"count": "$voteCount"
}
},
"total_count": { "$sum": "$voteCount" }
}
},
{ "$sort": { "total_count": -1 } }
Where I need to insert sort operation, to sort by count in descending order.
To sort an array during aggregation it is a bit tricky stuff.
So what I am duinfg to solve that is:
unwinding array
apply sort
regroup array
please find mongo shell code which will should give an overview ot this technique:
var group = {$group:{_id:"$type", votes:{$push:"$value" }}}
var unwind={$unwind:"$votes"}
var sort = {$sort:{"votes":-1}}
var reGroup = {$group:{_id:"$_id", votes:{$push:"$votes" }}}
db.readings.aggregate([group,unwind,sort ,reGroup])
any comments welcome!