Query using $dateFromString and $lt and $lge in mongodb - mongodb

I am trying to return some records for date range from mongodb and I am trying to use the following query to query the collection test for the field StartDate:
db.test.aggregate([
{
$match: {
"StartDate": {
"$gte": [
{
"$dateFromString": {
"dateString": "2021-03-01T00:00:00.0000000Z"
}
}
],
"$lt": [
{
"$dateFromString": {
"dateString": "2021-04-01T00:00:00.0000000Z"
}
}
]
}
}
}
])
The above query didn't return anything but I am sure there are some data between the dates. Any ideas what have I missed? Thanks!

The $dateFromString is a aggregation pipeline operator, so it requires to match in $expr expression condition, and expression have different syntax of $gte and $lt,
db.test.aggregate([
{
$match: {
$expr: {
$and: [
{
$gte: [
"$StartDate",
{
"$dateFromString": {
"dateString": "2021-03-01T00:00:00.0000000Z"
}
}
]
},
{
$lt: [
"$StartDate",
{
"$dateFromString": {
"dateString": "2021-04-01T00:00:00.0000000Z"
}
}
]
}
]
}
}
}
])
Playground
Second option: You can use $toDate operator alternate of $dateFromString,
Playground
Update as per new requirement:
Field activities.dateOfActivity is an array, it requires to iterate through loop and check each date's conditions,
$map to iterate loop of activities.dateOfActivity array and put both condition inside, it will return true if both condition satisfy otherwise return false
$anyElementTrue will check return array of boolean have any true condition then return document
db.test.aggregate([
{
$match: {
$and: [
{
"$expr": {
$anyElementTrue: {
$map: {
input: "$activities.dateOfActivity",
in: {
$and: [
{
"$gte": [
"$$this",
{
"$dateFromString": {
"dateString": "2021-03-01T00:00:00.0000000Z"
}
}
]
},
{
"$lt": [
"$$this",
{
"$dateFromString": {
"dateString": "2021-04-20T00:00:00.0000000Z"
}
}
]
}
]
}
}
}
}
}
]
}
}
])
Playground

Related

MongoDB - How to filter results of an lookup

I'm new to MongoDB.
My lookup gives me the following result, how can I filter through the results below in order to get expected_delivery_time, using MongoDB aggregate:
[
{
"from":"Jeddah",
"delivery_rule":[
{
"to":"Makkah",
"expected_delivery_time":3
},
{
"to":"Riyadh",
"expected_delivery_time":2
}
]
},
{
"from":"Riyadh",
"delivery_rule":[
{
"to":"Makkah",
"expected_delivery_time":3
},
{
"to":"Riyadh",
"expected_delivery_time":1
}
]
}
]
Below is my code:
{
$lookup:
{
from: "Setting",
pipeline: [
{
$match: {
$expr: {
{ $eq: ["$name", "delivery_rules"] }
}
}
],
as: "delivery_rules"
}
},
{ "$match": { "$delivery_rules.value.from": "Jeddah" } },
{ "$match": { "$delivery_rules.value.to": "Riyadh" } },
I need help with below MySQL equivalent to:
SELECT 'expected_delivery_time' WHERE from='Jeddah' AND to='Makkah'
Based on the $lookup stage, I expected the result documents should be:
[
{
"from": "Jeddah",
"delivery_rules": [
{
"to": "Makkah",
"expected_delivery_time": 3
},
{
"to": "Riyadh",
"expected_delivery_time": 2
}
]
},
{
"from": "Riyadh",
"delivery_rules": [
{
"to": "Makkah",
"expected_delivery_time": 3
},
{
"to": "Riyadh",
"expected_delivery_time": 1
}
]
}
]
delivery_rules (with "s", but the document you shared is with delivery_rule)
Both delivery_rules.value.from and delivery_rules.value.to don't exist. And you shouldn't use $ for the field in $match stage based on your query.
$lookup
$match - Filter from and delivery_rules.to. Combine 2 $match stages into 1.
$project - Decorate output document. Add expected_delivery_time field:
3.1. $getField - Get expected_delivery_time field from the result 3.1.1.
3.1.1. $first - Get the first value from the result 3.1.1.1 array.
3.1.1.1. $filter - Filter the document with to is "Makkah" in delivery_rules array.
db.collection.aggregate([
/* Lookup stage */
{
"$match": {
"from": "Jeddah",
"delivery_rules.to": "Riyadh"
}
},
{
$project: {
expected_delivery_time: {
"$getField": {
"field": "expected_delivery_time",
"input": {
$first: {
$filter: {
input: "$delivery_rules",
cond: {
$eq: [
"$$this.to",
"Makkah"
]
}
}
}
}
}
}
}
}
])
Sample Mongo Playground

How to find items in collection by string input?

In my collection users I have a field registerDate in format ISODate(< string >). I need to send a request to MongoDB. I use vibe.d framework and this one can send only deserialized JSON string. So, the input date can be either "2021-02-28T21:00:00Z" or UNIX timestamp.
In detail:
Works:
db.users.find(
{
"registerDate":{
"$gte": ISODate("2021-02-28T21:00:00Z"),
"$lt": ISODate("2021-10-31T21:00:00Z")
}
})
Doesn't work:
"$gte": {$date: "2021-02-28T21:00:00Z"},
"$lt": {$date:"2021-10-31T21:00:00Z"}
I also try:
db.users.aggregate([
{ "$project": {
"registerDate": {
"$gte": { "$toDate": "2021-01-07T23:39:49.178Z" },
"$lt": { "$toDate": "2021-09-07T23:39:49.178Z" }
}
}
}])
Then, I get the error:
"errmsg" : "Invalid $project :: caused by :: FieldPath field names may not start with '$'."
Try $expr expression operator to use aggregation operator in $match stage,
db.users.aggregate([
{
$match: {
$expr: {
$and: [
{
$gte: [
"$registerDate",
{ $toDate: "2021-02-28T21:00:00Z" }
]
},
{
$lt: [
"$registerDate",
{ $toDate: "2021-10-31T21:00:00Z" }
]
}
]
}
}
}
])
Playground

MongoDB - match multiple fields same value

So I am trying to do something where I can group MongoDB fields for a check.
Given I have following data structure:
{
//Some other data fields
created: date,
lastLogin: date,
someSubObject: {
anotherDate: date,
evenAnotherDate: date
}
On these I want to do a check like this:
collection.aggregate([
{
$match: {
"created": {
$lt: lastWeekDate
},
"someSubObject.anotherDate": {
$lt: lastWeekDate
},
"lastLogin": {
$lt ...
is there a possibility to group the fields and do something like
$match: {
[field1, field2, field3]: {
$lt: lastWeekDate
}
}
You need $expr to use $map to generate an array of boolean values and then $allElementsTrue to apply AND condition
db.collection.find({
$expr: {
$allElementsTrue: {
$map: {
input: [ "$field1", "$field2", "$field3" ],
in: { $lt: [ "$$this", lastWeekDate ] }
}
}
}
})
EDIT: if you need that logic as a part of aggregation you can use $match which is an equivalent of find
db.collection.aggregate([
{
$match: {
$expr: {
$allElementsTrue: {
$map: {
input: [ "$field1", "$field2", "$field3" ],
in: { $lt: [ "$$this", lastWeekDate ] }
}
}
}
}
}
])

$or query in mongodb

I need find field create_date, but if create_date is not defined, then find field create_time:
Sources_Timings.find({
create_date: {
$or: [
{
$gte: req.body.date.starting,
$lte: req.body.date.ending
},
{
$exists: false
}
]
},
create_time: {
$or: [
{
$gte: 0,
$lt: 86400000
},
{
$exists: false
}
]
}
},
function(err, timings) {
...
})
My code don't working.
$or is a top level operator and perform operation on an array of two or more expressions and selects the documents that satisfy at least one of the expressions.
So you query should be some thing like this
Sources_Timings.find({
"$or": [
{
"create_date": {
"$gte": req.body.date.starting,
"$lte": req.body.date.ending
}
},
{
"create_time": {
"$gte": 0,
"$lt": 86400000
}
}
]
})

how to query mongo a value with $lte and $in?

I have a document like:
{
_id:"1",
archive:[{mark:10},{mark:20},{mark:30},{mark:40}]
},
{
_id:"2",
archive:[{mark:12},{mark:25},{mark:30}]
},
{
_id:"3",
archive:[{mark:15},{mark:18}]
}
....
I want to find document where archive have {mark:30} but less then mark:30.
If I use query:
{archive:{$elemMatch:{ mark:{$lte:30}}}
will get document with 2,3
If I user query:
{archive:{$elemMatch:{ mark:{$lte:30,$in:[30]}}}
will get 1,2.
how to only get document 2?
Thank you!
You could try a query which would satisfy the logic
match documents where archive have { "mark": 30 } AND mark is NOT
greater than 30 (same as less than or equal to 30):
db.collection.find({
"archive.mark": {
"$eq": 30,
"$not": { "$gt": 30 }
}
})
or using the $and operator explicitly as
db.collection.find({
"$and": [
{ "archive.mark": 30 },
{ "archive.mark": { "$not": {
"$gt": 30
} } }
]
})
With $elemMatch
db.getCollection('yourCollection').find(
{
archive: {
$elemMatch: {
$and: [
{ mark: { $eq: 30 }},
{ mark: { $lte: 30 }},
{ mark: { $not: { $gt: 30 } } }
]
}
}
})