I want to filter classes that are still on going using $match with moment js. But, the $getField doesn't work as expected.
$match: {
$expr: {
$lt: [
moment(new Date()).valueOf(),
parseInt(moment({ $getField: "classStartDate" }, 'x').add({ $getField: "numberOfWeeks"}, 'weeks').valueOf())
]
}
}
Why so complicated? Simply try this:
$match: {
$expr: {
$lt: [
"$$NOW",
{$add: ["$classStartDate", {$multiply: ["$numberOfWeeks", 1000*60*60*24*7 ]} ] }
]
}
}
As you are obviously using Mongo version 5.0, you can also use
$match: {
$expr: {
$lt: [
"$$NOW",
{ $dateAdd: { startDate: "$classStartDate", unit: "week", amount: "$numberOfWeeks" } }
]
}
}
If $$NOW does not work use moment().toDate()
Related
I am trying to create a view for records created/modified in last 24 hours.
Is it possible?
Tried creating view as below
db.createView(
"viewname",
"sourcecollection",
[ { $match: {"modifiedTime":{$gte:new Date(Date.now() - 24*60*60*1000), $lte:new Date()}}}]
)
But it translates to static values
{
modifiedTime: {
$gte: ISODate('2022-10-25T23:20:21.602Z'),
$lte: ISODate('2022-10-26T23:20:21.602Z')
}
}
Did read about $$NOW but could not get it working in create view command.
Please suggest
Try this one:
db.createView(
"viewname",
"sourcecollection",
[
{
$match: {
$expr: {
$and: [
{ $gte: ["$modifiedTime", { $dateSubtract: { startDate: "$$NOW", unit: "day", amount: 1 } }] },
{ $lte: ["$modifiedTime", "$$NOW"] }
]
}
}
}
]
)
Based on above post, got it working in Mongo 4.4 with below command.
Dynamic view for records in last 24 hours.
db.createView(
"viewname",
"source",
[ { $match: {$expr: { $gte: [ "modifiedTime" , { $subtract: [ "$$NOW", 24*60*60*1000 ] } ] }}}]
)
I'm querying through Metabase which is connected to a Mongodb server. The field which I'm querying is nested and is a Unix timestamp. See below
{
room_data: {
"meta": {
"xxx_unrecognized": null,
"xxx_sizecache": 0,
"id": "Hke7owir4oejq3bMf",
"createdat": 1565336450838,
"updatedat": 1565336651548,
}
}
}
The query I have written is as follows
[
{
$match: {
client_id: "{{client_id}}",
"room_data.meta.createdat": {
$gt: "{{start}}",
$lt: "{{end}}",
}
}
},
{
$group: {
id: "$room_data.recipe.id",
count: {
$sum: 1
}
}
}
]
I do not get any result as the field room_data.meta.createdat is not a date (Aug 20, 2020) which I'm passing in. Here start and end are the parameters (Metabase feature) which I'm passing in the Date format. I need some help in converting those dates into unix timestamp which can then be used to filter out the results between the specific dates
If you're using Mongo version 4.0+ you can then use $toDate in you're aggregation like so:
db.collection.aggregate([
{
$match: {
$expr: {
$and: [
{
$eq: [
"$client_id",
{{client_id}}
]
},
{
$lt: [
{
$toDate: "$room_data.meta.createdat"
},
{{end}}
]
},
{
$gt: [
{
$toDate: "$room_data.meta.createdat"
},
{{start}}
]
}
]
}
}
}
])
MongoPlayground
If you're you're on an older Mongo version I recommend you either convert you're database fields to be Date type, or you convert your input into a number timestamp somehow (I'm unfamiliar with metabase).
The last option is to use $subtract as you can subtract a number from a date in Mongo, then check to see whether that date is before or after 1970-01-01T00:00:00Z. the problem with this approach is it does not consider timezones, so if your input's timezone is different than your database one or is dynamic this will be a problem you'll have to account for.
db.collection.aggregate([
{
$match: {
$expr: {
$and: [
{
$eq: [
"$client_id",
{{client_id}}
]
},
{
$gt: [
{
"$subtract": [
{{end}},
"$room_data.meta.createdat"
]
},
ISODate("1970-01-01T00:00:00.000Z")
]
},
{
$lt: [
{
"$subtract": [
{{start}},
"$room_data.meta.createdat"
]
},
ISODate("1970-01-01T00:00:00.000Z")
]
}
]
}
}
}
])
MongoPlayground
I have a collection in the following format:
Collection name: COLL1
{
_id: "a",
list: [
{
_id: "a1",
ranking: 10
},
{
_id: "a2",
ranking: 30
}
...
]
}
{
_id: "b",
list: [
{
_id: "b1",
ranking: 10
},
{
_id: "b2",
ranking: 30
}
...
]
}
When I call: db.getCollection('COLL1').find({"_id": "a","list._id": "a1"}); I can see the results. However, if I call:
db.getCollection('COLL1').aggregate([
{ $match:
{ $expr:
{ $and:
[
{ $eq: ["$_id", "a"] },
{ $eq: ["$list._id", "a1"] }
]
}
}
}
])
Then nothing is returned. Does anyone know why? I think the issue is { $eq: ["$list._id", "a1"] } but I'm not sure what exactly happened here.
I'm trying to get the complete document:
{
_id: "a",
list: [
{
_id: "a1",
ranking: 10
},
{
_id: "a2",
ranking: 30
}
...
]
}
This is part of my aggregate syntax within a $lookup stage, so I have to use aggregate([]) instead of find(). What I'm actually trying to achieve is the following:
...previous stages
{
$lookup:{
from: "COLL1",
let: { local_id: "$_id" }, // this '$_id' is from another collection, not COLL1.
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$_id", "a"] },
{ $eq: [ "$$local_id", "$list._id" ] } // this is where I got in trouble.
]
}
}
}
],
as: "matched_result"
}
},
Thanks a lot!
If you don't need variables from previous pipeline stages, you can just use the same syntax as .find() inside $match
db.getCollection('COLL1').aggregate([
{ $match: { "_id": "a", "list._id": "a1" } }
])
Replacing the second $eq with $in will work just fine. :)
db.getCollection('COLL1').aggregate([
{ $match:
{ $expr:
{ $and:
[
{ $eq: ["$_id", "a"] },
{ $in: ["a1", "$list._id"] }
]
}
}
}
])
How do I convert my object id to string so that I can compare it with string in $eq.
mongo version - 4.0
db.user.aggregate([{
$lookup:{
from: "sometable",
let:{user:["$_id"]},
pipeline:[{
$match: {
$expr: {
$and:[
{
$eq: [ "$userId", "$$user"]
},
{
$gt: [ "$lastBalance", 0]
}
]
}
}
}
],
as: "response"
},
}])
You can use $toString,
$eq: [ "$userId", {$toString: "$$user"}]
You can also try this:
$eq: [ {$toObjectId: "$$userId", "$user"}]
I don't know why but objectId comparisons are quicker it seems
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 ] }
}
}
}
}
}
])