MongoDB find document with Date field using a part of Date - regex

i want to search a date like the following:
09-11
03-22
and it will search in the available documents and bring the matched documnet.
an available document example :
2022-09-11T15:31:25.083+00:00
how can i do this?
i tried following query but that didn't work:
db.users.find({ createdAt: new RegExp('09-11') }) // Null

You can do it with aggregate query:
$toString - to convert date to string
$regexMatch - to apply regex search
db.collection.aggregate([
{
"$match": {
"$expr": {
"$regexMatch": {
"input": {
"$toString": "$createdAt"
},
"regex": "09-11"
}
}
}
}
])
Working example

Using aggregate you can extract $dayOfMonth and $month from initial date, filter using$match and after $project the initial document by excluding calculated day and month from the document.
db.users.aggregate([
{
$addFields: {
month: {
$month: "$createdAt"
},
day: {
$dayOfMonth: "$createdAt"
},
}
},
{
$match: {
month: 9,
day: 11
}
},
{
$project: {
month: 0,
day: 0
}
}
])

Related

Querying MongoDB with a regular expression in Rust

I am trying to implement the bucket pattern as solution to a previous question.
In the example they issue an update with a selector that uses a regular expression:
db.history.updateOne({ "_id": /^7000000_/, "count": { $lt: 1000 } },
{
"$push": {
"history": {
"type": "buy",
"ticker": "MDB",
"qty": 25,
"date": ISODate("2018-11-02T11:43:10")
} },
"$inc": { "count": 1 },
"$setOnInsert": { "_id": "7000000_1541184190" }
},
{ upsert: true })
I'm trying to do the same in Rust, but the query is interpreting my regex as a string literal and not evaluating the regex.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RepetitionBucketUpdate {
#[serde(with = "serde_regex")]
id: Regex,
device_id: Uuid,
session_id: Uuid,
set_id: Uuid,
exercise: String,
level: String,
count: mongodb::bson::Bson,
}
impl From<JsonApiRepetition> for RepetitionBucketUpdate {
fn from (value: JsonApiRepetition) -> Self {
let id = format!("^{}_", value.device_id.to_string().replace("-", ""));
let re = Regex::new(&id).unwrap();
RepetitionBucketUpdate {
id: re,
device_id: value.device_id,
session_id: value.session_id,
set_id: value.set_id,
exercise: value.exercise,
level: value.level,
count: mongodb::bson::bson!( { "$lt": BUCKET_RECORD_LIMIT }),
}
}
}
let update = bson::doc! {
"$push": {
"repetitions": mongodb::bson::to_bson(&repetition_update).unwrap(),
},
"$inc": { "count": 1 },
"$setOnInsert": { "id": oid }
};
let options = mongodb::options::UpdateOptions::builder()
.upsert(true)
.build();
collection.update_one(query, update, options).await.map_err(CollectorError::DbError)?;
If I println! the update parameters I see:
query: Document({"id": String("^6fcd683c20d5415da1341e7d2f780749_"), "device_id": String("6fcd683c-20d5-415d-a134-1e7d2f780749"), "session_id": String("8388e24d-e680-46f4-9205-b9e43e39a17a"), "set_id": String("53d5a3ec-5962-402d-8e8a-41e9c5e3e01f"), "exercise": String("Bench Press"), "level": String("WheelsWithinWheels"), "count": Document(Document({"$lt": Int32(1000)}))})
update: Document({"$push": Document(Document({"repetitions": Document(Document({"number": Int32(88), "rom": Double(69.42), "duration": Double(666.0), "time": Int64(10870198172412)}))})), "$inc": Document(Document({"count": Int32(1)})), "$setOnInsert": Document(Document({"id": String("6fcd683c20d5415da1341e7d2f780749_1600107371599537000")}))})
options: UpdateOptions {
array_filters: None,
bypass_document_validation: None,
upsert: Some(
true,
),
collation: None,
hint: None,
write_concern: None,
}
It's not matching, and it's inserting every update as a new document rather than bucketing subsequent updates.
I can successfully issue a regex based query from the mongodb shell. How do I query with a regex using Rust and mongodb as in the example?
I figured this out, so for anyone who has this problem in the future:
The mongodb driver does not use the Regex crate, instead the bson crate defines a Regex struct.
My usage changed from the above (see question) to:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RepetitionBucketUpdate {
pub id: mongodb::bson::Bson,
pub device_id: Uuid,
session_id: Uuid,
set_id: Uuid,
exercise: String,
level: String,
count: mongodb::bson::Bson,
}
let id = format!("^{}_", value.device_id.to_string().replace("-", ""));
let re = mongodb::bson::Regex {
pattern: id,
options: String::new(),
};
And voilà, ça marche!

Mongo DB searching for occurances by date

So I've got a large dataset stored in my MonogDB of each time a song has been played in my itunes library, so each document is contains the artist name, song name, and date/time it was played. I currently am able to use the following query to search for the most occurances of a song in the database, which basically gives me the total number of times i had played it:
db.apple.aggregate([{ $sortByCount: "$song" }])
Returns:
{ "_id" : "Fireflies (feat. Grieves)", "count" : 336 }
{ "_id" : "Cinderella (feat. Ty Dolla $ign)", "count" : 267 }
{ "_id" : "Check", "count" : 241 }
{ "_id" : "100 Grandkids", "count" : 240 }
{ "_id" : "Late For the Sky (feat. Slug & Aesop Rock)", "count" : 226 }
This returns the total number of plays i have on a song, over the 5 years of plays i have in the database. What i was hoping to be able to do is create a query where it returns the total number of plays of a song for a specific year. I have the following query:
db.apple.find({"playTime" : {$regex : ".*2019*"}}).pretty()
This one returns all the songs that were played in a year but i can't figure out how i would combine these two queries.
Assuming playTime is a string data type ({ "playTime" : "2017-06-17T06:04:40.230Z" }), extract the first 4 characters of the string using the $substrCP and convert to an integer and match with an input year. The $sortByCount stage will remain as it is. The conversion to integer is optional; if not used the input year should be a string.
For example (using integer year):
var INPUT_YEAR = 2017
db.test.aggregate( [
{
$match: {
$expr: {
$eq: [ INPUT_YEAR, { $toInt: { $substrCP: [ "$playTime", 0, 4 ] } } ]
}
}
},
{
$sortByCount: "$song"
}
] )
Since you already have the queries ready, you just need to put them both in the same aggregation pipeline as JBone suggested in the comments. If your queries work as you have mentioned, this will do the trick:
db.apple.aggregate([
{ $sortByCount: "$song" },
{ $match: { "playTime" : {$regex : ".*2019*"} } }
])
If playTime is a string of type ISO 8601 format, then you can try this :
db.apple.aggregate([{
$match: {
$expr: {
$eq: [2019, {
$year: {
$dateFromString: {
dateString: '$playTime'
}
}
}]
}
}
}, { $sortByCount: "$song" }])
Or in case if you can change it to/have ISODate() then :
db.apple.aggregate([{
$match: {
$expr: {
$eq: [2019, {
$year: '$playTime'
}]
}
}
}, { $sortByCount: "$song" }])
Ref : $year,$dateFromString,$match or $isoWeekYear

How to exclude substring in Elasticsearch regexp

I'm trying to write an elasticsearch regexp that excludes elements that have a key that contains a substring, let's say in the title of books.
The elasticsearch docs suggest that a substring can be excluded with the following snippet:
#&~(foo.+) # anything except string beginning with "foo"
However, in my case, I've tried to create such a filter and failed.
{
query: {
constant_score: {
filter: {
bool: {
filter: query_filters,
},
},
},
},
size: 1_000,
}
def query_filters
[
{ regexp: { title: "#&~(red)" } },
# goal: exclude titles that start with "Red"
]
end
I've used other regexp in the same query filter that have worked, so I don't think there's a bug in the way the regexp is being passed to ES.
Any ideas? Thanks in advance!
Update:
I found a workaround: I can add a must_not clause to the filter.
{
query: {
constant_score: {
filter: {
bool: {
filter: query_filters,
must_not: must_not_filters,
},
},
},
},
size: 1_000,
}
def must_not_filters
[ { regexp: { title: "red.*" } } ]
end
Still curious if there's another idea for the original regex though

Regex in Mongodb for ISO Date field

How can I pick all the dates with time value as 00:00:00 despite the date value? Regex doesn't work for me.
{
"_id" : ObjectId("59115a92bbf6401d4455eb21"),
"name" : "sfdfsdfsf",
"create_date" : ISODate("2013-05-13T02:34:23.000Z"),
}
something like :
db.myCollection.find({"create_date": /*T00:00:00.000Z/ })
You need to first convert created date into string of time, and if time is 00:00:00:000, then include the document.
db.test.aggregate([
// Part 1: Project all fields and add timeCriteria field that contain only time(will be used to match 00:00:00:000 time)
{
$project: {
_id: 1,
name: "$name",
create_date: "$create_date",
timeCriteria: {
$dateToString: {
format: "%H:%M:%S:%L",
date: "$create_date"
}
}
}
},
// Part 2: match the time
{
$match: {
timeCriteria: {
$eq: "00:00:00:000"
}
}
},
// Part 3: re-project document, to exclude timeCriteria field.
{
$project: {
_id: 1,
name: "$name",
create_date: "$create_date"
}
}
]);
From MongoDB version >= 4.4 we can write custom filters using $function operator.
Note: Donot forget to chage the timezone to your requirement. Timezone is not mandatory.
let timeRegex = /.*T00:00:00.000Z$/i;
db.myCollection.find({
$expr: {
$function: {
body: function (createDate, timeRegex) {
return timeRegex.test(createDate);
},
args: [{ $dateToString: { date: "$create_date", timezone: "+0530" } }, timeRegex],
lang: "js"
}
}
});

Using regular expressions in elasticsearch term queries

I want find all items filtered by ID match some regular expression like
*TEST123* //pattern for regexp
So expected result are items
ATEST123001
ATEST123002
ATEST123003
TTTTEST123001
...
I can create some script which scan full storage and save IDs in log-file which can check later. But I want to find some better solution
Updated
I tried
"query" : { "match_all" : { }, "filtered" : { "filter" : { "regexp": { "id":".test123." } } } }, }
I receive
//nested: ElasticsearchParseException[Expected field name but got START_OBJECT \"filtered\"]
When I tried
{
"regexp": {
"id": "test123"
}
}
//Parse Failure [No parser for element [regexp]]]
ES 1.7.4 and Lucene 4.10.4
You can use regular expression queries. The regexp query allows you to use regular expression term queries.
Ref:
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html
Sample regex query :
{
"regexp":{
"id": "*test123*"
}
}
Update:
In 2.0 regexp filter has been replaced by regexp query.
{
"query": {
"filtered": {
"filter": {
"regexp":{
"id":".*TEST123.*"
}
}
}
}
}
You can try Query String.
{
"query": {
"query_string": {
"default_field": "if",
"query": "*test123*"
}
}
}