How to find in specific date interval - database

I have problem in Mongodb to find wanted documents and fragment of list field. So I have following document:
{
"_id": "5ed38e5d2a6e74567c7a579c",
"id": "AAA",
"events": [
{
"dayTypeId": "5e71e1918ee9a326ebdf1611",
"startDate": {
"$date": "2020-06-01T00:00:00.000Z"
},
"endDate": {
"$date": "2020-06-04T00:00:00.000Z"
},
"stared": false,
"userId": "XXX",
"mixing": "wjk0ra1v7m88p0x5aaxwndkmwmlxx4pn92hzjlgpl34u8ojx855m8e8spp1v7l57omtoc4qxbv0g22nybqubd3hq5skuff8ezbzdum2a92itwco64tbi5y2p5mboznxiuwynv0rb8eqk9d80ib65cve6ab9p1d1divee3wbywc2st1lkjruqvgu42zgx8mjtsnb8gyeqtxycl4ujpllgxpshdu8o97iiw347bjqv4mrv6jgwq4r21zp5rm4dw6a1"
},
{
"dayTypeId": "5e71e1918ee9a326ebdf1611",
"startDate": {
"$date": "2020-06-10T00:00:00.000Z"
},
"endDate": {
"$date": "2020-06-10T00:00:00.000Z"
},
"stared": false,
"userId": "XXX",
"mixing": "wjk0ra1v7m88p0x5aaxwndkmwmlxx4pn92hzjlgpl34u8ojx855m8e8spp1v7l57omtoc4qxbv0g22nybqubd3hq5skuff8ezbzdum2a92itwco64tbi5y2p5mboznxiuwynv0rb8eqk9d80ib65cve6ab9p1d1divee3wbywc2st1lkjruqvgu42zgx8mjtsnb8gyeqtxycl4ujpllgxpshdu8o97iiw347bjqv4mrv6jgwq4r21zp5rm4dw6a1"
},
{
"dayTypeId": "5e71d8628ee9a326e7df160d",
"startDate": {
"$date": "2020-06-05T00:00:00.000Z"
},
"endDate": {
"$date": "2020-06-09T00:00:00.000Z"
},
"stared": false,
"userId": "XXX",
"mixing": "wjk0ra1v7m88p0x5aaxwndkmwmlxx4pn92hzjlgpl34u8ojx855m8e8spp1v7l57omtoc4qxbv0g22nybqubd3hq5skuff8ezbzdum2a92itwco64tbi5y2p5mboznxiuwynv0rb8eqk9d80ib65cve6ab9p1d1divee3wbywc2st1lkjruqvgu42zgx8mjtsnb8gyeqtxycl4ujpllgxpshdu8o97iiw347bjqv4mrv6jgwq4r21zp5rm4dw6a1"
},
{
"dayTypeId": "5e71d8628ee9a326e7df160d",
"startDate": {
"$date": "2020-07-13T00:00:00.000Z"
},
"endDate": {
"$date": "2020-07-21T00:00:00.000Z"
},
"stared": false,
"userId": "XXXX",
"mixing": "wjk0ra1v7m88p0x5aaxwndkmwmlxx4pn92hzjlgpl34u8ojx855m8e8spp1v7l57omtoc4qxbv0g22nybqubd3hq5skuff8ezbzdum2a92itwco64tbi5y2p5mboznxiuwynv0rb8eqk9d80ib65cve6ab9p1d1divee3wbywc2st1lkjruqvgu42zgx8mjtsnb8gyeqtxycl4ujpllgxpshdu8o97iiw347bjqv4mrv6jgwq4r21zp5rm4dw6a1"
}
]
}
I want to get fragment of "events" list where either the startDate or the endDate is in the range of 02.06.2020-11.06.2020.
For example out of my sample data I want all but the last element to be returned.

You can use $filter to filter out any events that do not match your conditions:
db.collection.aggregate([
{
$match: {
$or: [
{
"events.startDate": {$gte: new Date("2020-06-02"), $lte: new Date("2020-06-11")}
},
{
"events.endDate": {$gte: new Date("2020-06-02"), $lte: new Date("2020-06-11")}
}
]
}
},
{
$project: {
events: {
$filter: {
input: "$events",
as: "event",
cond: {
$or: [
{
$and: [
{$gte: ["$$event.startDate", new Date("2020-06-02")]},
{$lte: ["$$event.startDate", new Date("2020-06-11")]},
]
},
{
$and: [
{$gte: ["$$event.endDate", new Date("2020-06-02")]},
{$lte: ["$$event.endDate", new Date("2020-06-11")]},
]
}
]
}
}
}
}
}
])

Related

push object into array field in document in mongoDb

Schema
{
userid:{type:String,required:true,unique:false},
products:[{
productid:{
type:String
},
quantity:{
type:Number,
default:1,
},
}],
}
existing document:
{
"_id": {
"$oid": "633a8a8a3cb2f7a3e9703261"
},
"userid": "633a8a833cb2f7a3e970325c",
"products": [
{
"productid": "633993d09725095d71b071db",
"quantity": 1,
"_id": {
"$oid": "633a8a8a3cb2f7a3e9703262"
}
}
],
"createdAt": {
"$date": {
"$numberLong": "1664780938934"
}
},
"updatedAt": {
"$date": {
"$numberLong": "1664780938934"
}
},
"__v": 0
}
now i want to push below object to products array
"products":{productid:"6786879",quantity,2}
i tried below command (carts is collection name)
db.carts.update( { userid : "633a8a833cb2f7a3e970325c" },{ $push: { "products":
{productid:"6786879",quantity,2} } });
it throws below error :
clone(t={}){const r=t.loc||{};return e({loc:new Position("line"in r?
r.line:this.loc.line,"column"in r?r.column:......)} could not be cloned.
please anyone could help me

How to find array's object property(string) by its numeric value in mongodb query?

I have a restaurant collection with its documents formed like this one:
{
"address": {
"building": "1007",
"coord": [
-73.856077,
40.848447
],
"street": "Moris Park Ave",
"zipcode": "10462"
},
"borough": "Bronx",
"cuisine": "Bakery",
"grades": [
{
"date": {
"$date": 1393804800000
},
"grade": "A",
"score": "81"
},
{
"date": {
"$date": 1378857600000
},
"grade": "A",
"score": "6"
},
{
"date": {
"$date": 1358985600000
},
"grade": "A",
"score": "99"
},
{
"date": {
"$date": 11322006400000
},
"grade": "B",
"score": "14"
},
{
"date": {
"$date": 1288715200000
},
"grade": "B",
"score": "14"
}
],
"name": "Morris Park Bake Shop"
}
My homework asked me to find any restaurants having score from 80 to 100 and I do this
db.restaurants.find({ $expr: {$and: [{$gt: [ { $toInt: "$grades.score" }, 80 ]}, {$lt: [ { $toInt: "$grades.score" }, 100 ]}] } }).pretty()
And received "Executor error during find command :: caused by :: Unsupported conversion from array to int in $convert with no onError value".
I try
db.restaurants.find({ $expr: {$and: [{$gt: [ { $toInt: "$grades.$score" }, 80 ]}, {$lt: [ { $toInt: "$grades.$score" }, 100 ]}] } }).pretty()
And this returned:"FieldPath field names may not start with '$'. Consider using $getField or $setField."
Then i try
db.restaurants.find({$and:[{'grades.score': {$gt: 80}}, {'grade.score':{$lt:100}}]}).collation({locale:'en_US' ,numericOrdering: true})
And that returned nothing. It has to return at least the document i mentioned above, right?.
Perhaps this homework is about learning proper field value types or collation. With collation, numericOrdering can be used as commented by #prasad_. If score is truly numeric, for several reasons it's best to store it as numeric.
Unfortunately there doesn't seem to be a way at this time to specify a collation with mongoplayground.net. Without using a collation, there are many ways to achieve your desired output. Here's one way.
db.collection.aggregate([
{
// make grades.score numeric
"$set": {
"grades": {
"$map": {
"input": "$grades",
"as": "grade",
"in": {
"$mergeObjects": [
"$$grade",
{ "score": { "$toDecimal": "$$grade.score" } }
]
}
}
}
}
},
{
"$match": {
"grades.score": {
"$gt": 80,
"$lt": 100
}
}
},
{
"$project": {
"_id": 0,
"name": 1
}
}
])
Try it on mongoplayground.net.

How to use projection for nested value in mongod

How to use projection to view only the below part from all docs of the collection?
Conditions:
I need to fetch only for "type": "DEBIT" and below 2 lines, NOT all other keys in the same type.
I dont want to view other types like Account, Deposit.
{
"key": "Call",
"enabled": true,
}
Sample Docs which i have in the below structure.
{
"_id": "1",
"menu": [
{
"type": "ACCOUNT",
"scope": "ACCOUNT",
"items": [
{
"key": "Call",
"enabled": true,
},
{
"key": "Work",
"enabled": true,
}
]
},
{
"type": "DEPOSIT",
"scope": "DEPOSIT",
"items": [
{
"key": "Call",
"enabled": true,
},
{
"key": "Work",
"enabled": true,
}
]
},
{
"type": "DEBIT",
"scope": "DEBIT",
"items": [
{
"key": "Call",
"enabled": true,
},
{
"key": "Work",
"enabled": true,
}
]
},
]
}
first, you need to $unwind the menu
then $match type debit
and filter array items and then group to create the final result
db.collection.aggregate([
{
"$unwind": "$menu"
},
{
$match: {
"menu.type": "DEBIT"
}
},
{
"$project": {
_id: 1,
"menu.items": {
"$filter": {
"input": "$menu.items",
"as": "s",
"cond": {
$and: [
{
$eq: [
"$$s.enabled",
true
]
},
{
$eq: [
"$$s.key",
"Call"
]
}
]
}
}
}
}
},
{
"$group": {
"_id": "$_id",
"menu": {
"$push": "$menu"
}
}
}
])
https://mongoplayground.net/p/kRChgF9rLsI
use $filter
db.collection.aggregate([
{
"$match": {
"menu.type": "DEBIT"
}
},
{
"$set": {
"menu": {
"$filter": {
"input": "$menu",
"as": "m",
"cond": {
$eq: [
"$$m.type",
"DEBIT"
]
}
}
}
}
}
])
mongoplayground

How to reverse $unwind or re-assemble after $lookup?

I´ve been trying to reverse $unwind in nested array. Please, if you could help me it would be great. Thanks in advance.
Here are the details:
checklists collection, this collection has steps and each step has many areas, and I'd like to lookup to fill the area by id. I did it but I cannot reverse $unwind.
{
"steps": [{
"name": "paso1",
"description": "paso1",
"estimated_time": 50,
"active": true,
"areas": [{
"area_id": "60b6e728c44f0365c0d547d6"
}, {
"area_id": "60b6e7a2c44f0365c0d547d8"
}]
}, {
"name": "paso2",
"description": "o",
"estimated_time": 7,
"active": true,
"areas": [{
"area_id": "60b6e76ac44f0365c0d547d7"
}]
}, {
"name": "paso2",
"description": "l",
"estimated_time": 7,
"active": true,
"areas": [{
"area_id": "60b6e728c44f0365c0d547d6"
}]
}],
"name": "prueba",
"description": "prueba",
"type": "prueba",
"active": true,
"updated_at": {
"$date": "2021-06-02T23:56:02.232Z"
},
"created_at": {
"$date": "2021-06-01T22:44:57.114Z"
},
"__v": 0
}
area collection
{
"_id":"60b6e706c44f0365c0d547d5"
"name": "Development",
"short_name": "DEV",
"description": "Development area",
"updated_at": {
"$date": "2021-06-02T02:03:50.383Z"
},
"created_at": {
"$date": "2021-06-02T02:03:50.383Z"
},
"__v": 0,
"active": true
}
My aggregation
db.checklists.aggregate([
{
"$unwind": "$steps"
},
{
"$unwind": "$steps.areas"
},
{
"$lookup": {
"from": "areas",
"let": {
"area_id": {
"$toObjectId": "$steps.areas.area_id"
}
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$_id",
"$$area_id"
]
}
}
}
],
"as": "convertedItems"
}
},
{
"$group": {
"_id": "$steps.name",
"root": {
"$first": "$$ROOT"
},
"items": {
"$push": {
"$mergeObjects": [
"$steps.areas",
{
"$arrayElemAt": [
"$convertedItems",
0
]
}
]
}
},
}
},
{
"$addFields": {
"values": {
"$reduce": {
"input": "$items",
"initialValue": [],
"in": {
"$concatArrays": [
"$$value",
{
"$cond": [
{
"$in": [
"$$this.area_id",
"$$value.area_id"
]
},
[],
[
"$$this"
]
]
}
]
}
}
}
}
},
{
"$addFields": {
"root.steps.areas": "$values"
}
},
{
"$replaceRoot": {
"newRoot": "$root"
}
},
{
"$group": {
"_id": "$_id",
"root": {
"$first": "$$ROOT"
},
"steps": {
"$push": "$steps"
}
}
},
{
"$addFields": {
"root.steps": "$steps"
}
},
{
"$replaceRoot": {
"newRoot": "$root"
}
},
{
"$project": {
"convertedItems": 0
}
}
])
I don´t get to form this output:
{
"steps": [{
"name": "paso1",
"description": "paso1",
"estimated_time": 50,
"active": true,
"areas": [{
"_id": "60b6e728c44f0365c0d547d6",
"name":"Development",
..... //join or lookup
}, {
"_id": "60b6e7a2c44f0365c0d547d8",
"name":"Development",
..... //join or lookup
}]
}],
"name": "prueba",
"description": "prueba",
"type": "prueba",
"active": true,
"updated_at": {
"$date": "2021-06-02T23:56:02.232Z"
},
"created_at": {
"$date": "2021-06-01T22:44:57.114Z"
},
"__v": 0
}
Thank you very much!
$unwind deconstruct steps array
$lookup with areas collection pass area_id in let
$match to check is _id in area_ids after converting to string
$project to show required fields
$group by _id and reconstruct the steps array and pass your required fields
db.checklists.aggregate([
{ $unwind: "$steps" },
{
$lookup: {
from: "areas",
let: { area_id: "$steps.areas.area_id" },
pipeline: [
{
$match: {
$expr: { $in: [{ $toString: "$_id" }, "$$area_id"] }
}
},
{ $project: { name: 1 } }
],
as: "steps.areas"
}
},
{
$group: {
_id: "$_id",
steps: { $push: "$steps" },
name: { $first: "$name" },
description: { $first: "$description" },
type: { $first: "$type" },
active: { $first: "$active" },
updated_at: { $first: "$updated_at" },
created_at: { $first: "$created_at" },
__v: { $first: "$__v" }
}
}
])
Playground

Get inner array value based on condition with other values in mongoose

I have a DB structure as follows:
{
"Title": "AAA",
"Photos": ["/aaa/aaa.png"],
"Loc": "XXX",
"Emp": "SSS",
"Rate": [{
"Rating": 2,
"RateID": "12345654654",
"RatedDate": new Date()
}],
"Fav": [{
"FavValue": 2,
"FavID": "1111",
"FavDate": new Date()
}]
}
Here, I want to fetch all the details by default. But from array, i need to get the object that matches the ID.
In "Rate" array it needs to match "RateID" and in "Fav" array it need to match "FavID".
Both "Rate" and "Fav" wont contains objects always.
I have tried foll mongoose aggregate:
ss.aggregate([
{ $unwind: "$Rate" },
{
$group: {
"_id": '$_id',
"Title": { "$first": "$Title" },
"Loc": { "$first": "$Loc" },
"Emp": { "$first": "$Emp" },
"Photos": { "$first": "$Photos" },
"Rate": { $max: { $cond: [ { $eq: [ "$Rate.RateID", new ObjectId(id) ] }, '$Rate.Rating', null ] } },
"Fav": { $max: { $cond : [ { $eq : [{ "$size": "$Fav" }, 0]}, null, { $cond: [ { $eq: [ "$Fav.FavID", new ObjectId(id) ] }, '$Fav.FavValue', null ] } ]} }
}
}
], function (err, AvgResult) {
res.json({"result": AvgResult});
});
For "Rate", if the array is empty it returns empty result as {}
For "Fav", it returns null always if the array is empty or if it contains object
If I send the ID as '12345654654', the result should be like
{
"Title": "AAA",
"Photos": ["/aaa/aaa.png"],
"Loc": "XXX",
"Emp": "SSS",
"Rate": 2,
"Fav": null
}
If the ID is "1111", the result should be
{
"Title": "AAA",
"Photos": ["/aaa/aaa.png"],
"Loc": "XXX",
"Emp": "SSS",
"Rate": null,
"Fav": 2
}
If "Fav" is empty array in DB like "Fav": [] and ID - is "12345654654", then the result should be as follows
{
"Title": "AAA",
"Photos": ["/aaa/aaa.png"],
"Loc": "XXX",
"Emp": "SSS",
"Rate": 2,
"Fav": null
}
can any one help to get the expected result in all the above scenario..

Resources