Finding values in mongodb collection with multiple occurence - mongodb

I have a collection with documents as follows :
{id: 1, "year": "12", "type": "checking", "location": "nyc", "category" : "Admin"}
{id: 2, "year": "15", "type": "checking", "location": "ma", "category": "Normal"}
{id: 3, "year": "12", "type": "credit", "location": "nyc","category": "Admin"}
{id: 4, "year": 12, "type": "checking", "location": "nyc", "category" : "Admin"}
Now, i want to count the 'type' that appears more than once meeting the criteria location:nyc, year:12, category: Admin
So the desired result is
{"Checking": 2}
What way can I achieve the above?

Use $match and $group
db.collectionname.aggregate({$match: {location: 'nyc', year:'12', category:'Admin'}},
{$group: {_id:'$type', count:{$sum:1}}},
{$match:{count: {$gt:1}}}
)

Related

Strange MongoDB $setIntersection behaviour

I want to query a match between records in my db based on certain tags. The match would be calculated based on a formula and the intersection of the tags. Now, even querying the intersection doesn't work...always. Sometimes it does, sometimes it doesn't. In my example, if I change the displayName attribute to something else (add or remove one character, the query works. In its current state (for demo purposes) it doesn't as it does not deliver the one intersection match for the last doc with id 3.
https://mongoplayground.net/p/KAYPoV29RFO
That's my query:
db.collection.aggregate([
{
$match: {
"_id": "1"
}
},
{
"$lookup": {
from: "collection",
let: {
"criteria": "$tags"
},
pipeline: [
{
$project: {
"match": {
$setIntersection: [
"$tags",
"$$criteria"
]
},
}
}
],
as: "result"
}
},
{
$project: {
"tags": 0
}
},
])
Here is the example data (simplified):
[
{ "_id": "1", "tags": [{ "_id": "a", "displayName": "a", "level": 1}, {"_id": "b", "displayName": "b", "level": 2}, {"_id": "c", "displayName": "c", "level": 3}]},
{"_id": "2", "tags": [{"_id": "a", "displayName": "a", "level": 1}, {"_id": "b", "displayName": "b", "level": 2}]},
{"_id": "3", "tags": [{"_id": "a", "displayName": "a", "level": 1}, {"_id": "d", "displayName": "d", "level": 4}]}
]
and the result as it is: (expected is three matches for id 1, 2 matches for id 2 and one for the last id. However, the last result has 0 elements in the intersection result. Again, when i change "displayName" to "displayNam" or "displayNames" (obviously in all docs), it give the correct result...
[{
"_id": "1", "result": [
{"_id": "1", "match": [{"_id": "a", "displayName": "a", "level": 1}, {"_id": "b", "displayName": "b", "level": 2},{"_id": "c","displayName": "c","level": 3}]},
{"_id": "2", "match": [{"_id": "a", "displayName": "a", "level": 1}, {"_id": "b", "displayName": "b", "level": 2}]},
{"_id": "3","match": [*here should be the match to _id: "a", but it's not (always) there*]}
]
}]
Does anyone have an idea what I am missing here?

How to update specific field in mongoDB given conditions?

Given the following mongdoDB structure, how can i update the field isAvailable to false given that the shopName is "jamrt" and slug is "67626dae-1537-40d8-837d-483e5759ada0". This is my query but it does not work: Shop.find({ shopName: shopName}).update({products: {$elemMatch: {slug: slug}}}, { $set: { isAvailable: req.body.isAvailable} } Thanks!
"shopName": "jmart",
"products": [{
"id": 1,
"name": "Clean and Clear Deep Clean Cleanser 100g",
"slug": "8d1c895c-6911-4fc8-a34c-89c6948233d7",
"price": 4.5,
"discount_price": 0,
"category": "Health and Beauty",
"sale": false,
"subcategory": "personal care",
"color": "black",
"article": "Clean and Clear",
"quantity": 9,
"img": "https://firebasestorage.googleapis.com/v0/b/swifty-products.appspot.com/o/Jmart%2FBeauty%2FClean%20and%20Clear%20Deep%20Clean%20Cleanser%20100g.jpg?alt=media",
"vendor": {
"id": 1,
"name": "Clean and Clear"
},
"ratings": {
"star_ratings": 0,
"votes": 0
},
"isAvailable": true
}, {
"id": 2,
"name": "Colgate Total Pro Breath Health",
"slug": "67626dae-1537-40d8-837d-483e5759ada0",
"price": 4.5,
"discount_price": 0,
"category": "Health and Beauty",
"sale": false,
"subcategory": "personal care",
"color": "black",
"article": "Colgate",
"quantity": 9,
"img": "https://firebasestorage.googleapis.com/v0/b/swifty-products.appspot.com/o/Jmart%2FBeauty%2FColgate%20Total%20Pro%20Breath%20Health.jpg?alt=media",
"vendor": {
"id": 2,
"name": "Colgate"
},
"ratings": {
"star_ratings": 0,
"votes": 0
},
"isAvailable": true
},
]
In your case, you are trying to update only the matching sub documents.
The $elemMatch operator while using in projection updates only the first matching sub document.
The $elemMatch operator while using in find updates all the fields of the matching document.
This solution might help you.
With your case, the solution might be the below in mongodb query:
db.Shop.update({"shopName":"jmart","products.slug":"67626dae-1537-40d8-837d-483e5759ada0"}, {$set: {“products.$[i].isAvailable”: false}}, {arrayFilters: [{“i.slug”: "67626dae-1537-40d8-837d-483e5759ada0"}]})

Sum value of elements and update field Mongo db

How Can I sum price on array "Elemets" and set on Document field Value?
I know how to do It in sql but I,m beginner in mongo.
{
"Document": [
{
"Id": 1,
"Type": "FV",
"Number": 34521,
"Year": 2020,
"Date": "2020-01-01T00:00:00",
"Value": 27.68,
"Elements": [
{
"Id": 1,
"DocumentId": 1,
"ProductId": 1,
"Quantity": 5.00,
"Price": 17.50,
"Task": 0.23
},
{
"Id": 2,
"DocumentId": 1,
"ProductId": 2,
"Quantity": 3.00,
"Price": 24.50,
"Task": 0.23
},
]
},
If you are using MongoDB 4.2, you can use $reduce to calculate the sum in the pipeline form of update.

select documents grouped by field

I have this documents of movie showing time and date:
`{
"_id": ObjectId("5628668c3e82c49245b7acdc"),
"ticketID": ObjectId("5606d36b5fbd7d76028b4b08"),
"uid": "50000",
"day": "Friday",
"date": "2015-10-23 21:05:00",
"adult": NumberLong(550),
"student": NumberLong(550),
"children": NumberLong(250),
"limit": NumberLong(20),
"sold": NumberLong(0)
},{
"_id": ObjectId("562866013e82c49045b7acdc"),
"ticketID": ObjectId("5606d36b5fbd7d76028b4b08"),
"uid": "50000",
"day": "Friday",
"date": "2015-10-23 19:30:00",
"adult": NumberLong(1050),
"student": NumberLong(800),
"children": NumberLong(550),
"limit": NumberLong(20),
"sold": NumberLong(0)
},{
"_id": ObjectId("562865013e82c49845b7acda"),
"ticketID": ObjectId("5606d36b5fbd7d76028b4b08"),
"uid": "50000",
"day": "Friday",
"date": "2015-10-23 18:45:00",
"adult": NumberLong(1500),
"student": NumberLong(750),
"children": NumberLong(750),
"limit": NumberLong(20),
"sold": NumberLong(0)
}
`
I want to group the final result by "day" where "ticketID" matches, "date" as an object and adding "adult","student","children","limit" to an array
-- UPDATE --
I would like the returned structure to follow:
{
"_id": "ticketID",
"day": "Friday",
"items": [
{
"date": date,
"time": time"adult": price,
"children": price,
"student": price,
"limit": value
},
{
"date": date,
"time": time"adult": price,
"children": price,
"student": price,
"limit": value
},
{
"date": date,
"time": time"adult": price,
"children": price,
"student": price,
"limit": value
}
]
}
Run the following aggregation pipeline which uses the $group operator to group your documents by the specified fields, add the items array by using the accumulator operator $push that returns an array of expression values for each group. The $project pipeline operator then reshapes the documents by amending the fields to get the final desired structure:
var pipeline = [
{
"$group": {
"_id": {
"ticketID": "$ticketID",
"day": "$day"
},
"items": {
"$push": {
"date": "$date",
"time": "$time",
"adult": "$adult",
"children": "$children",
"student": "$student",
"limit": "$limit"
}
}
}
},
{
"$project": {
"_id": "$_id.ticketID",
"day": "$_id.day",
"items": 1
}
}
];
db.collection.aggregate(pipeline);

Finding documents that are valid on a specific date

I have some data stored in a mongodb collection similar to:
{"_id": 1, "category": "food", "name": "chips", "price": 1.50, "effectiveDate": ISODate("2013-03-01T07:00:00Z")}
{"_id": 2, "category": "food", "name": "chips", "price": 1.75, "effectiveDate": ISODate("2013-03-05T07:00:00Z")}
{"_id": 3, "category": "food", "name": "chips", "price": 1.90, "effectiveDate": ISODate("2013-03-10T07:00:00Z")}
{"_id": 4, "category": "beverage", "name": "pop", "price": 2.00, "effectiveDate": ISODate("2013-03-01T07:00:00Z")}
{"_id": 5, "category": "beverage", "name": "pop", "price": 2.25, "effectiveDate": ISODate("2013-03-05T07:00:00Z")}
{"_id": 6, "category": "beverage", "name": "pop", "price": 1.80, "effectiveDate": ISODate("2013-03-10T07:00:00Z")}
In mongodb, how would I go about writing a query that would return the documents that were active on a specific date, grouped by the category?
If I specified March 6, 2013 I'd expect to see the results:
{"_id": 2, "category": "food", "name": "chips", "price": 1.75, "effectiveDate": ISODate("2013-03-05T07:00:00Z")}
{"_id": 5, "category": "beverage", "name": "pop", "price": 2.25, "effectiveDate": ISODate("2013-03-05T07:00:00Z")}
I am new to mongo and have been trying to do this using group, aggregate and mapreduce but have been just spinning in circles.
To give you a real good answer, I need more details of your code and what you are trying to do. But if I understand right, I think you can solve that using only the aggregation framework. You should know that the aggregation framework uses the pipeline concept, in other words, the result of each step is used as the entry to the following.
My query:
db.yourcollection.aggregate([
/* First exclude everything that is superior to a given date */
{$match:{effectiveDate:{$lte:new Date(2013,2,6)}}},
/* Sort the rest by date, descending */
{$sort:{effectiveDate:-1}},
/* Group by name+category and grab only the first result
(the newest below that date) */
{$group:{_id:{name:'$name',category:'$category'}, effectiveDate:{$first:"$effectiveDate"},price:{$first:"$price"}}},
/* You said you want the results grouped by category.
This last $group does that and returns all matching products inside an array
It also removes the duplicates */
{$group:{_id:'$_id.category',products:{$addToSet:{name:"$_id.name",price:"$price",effectiveDate:"$effectiveDate"}}}}
])
The output is like this:
{
"result": [
{
"_id": "food",
"products": [
{
"name" : "chips",
"price" : 1.75,
"effectiveDate" : ISODate("2013-03-05T07:00:00Z")
}
]
},
{
"_id" : "beverage",
"products": [
{
"name" : "pop",
"price" : 2.25,
"effectiveDate" : ISODate("2013-03-05T07:00:00Z")
}
]
}
],
"ok":1
}
You can change the final output modifing the last $group or using a $project