couchdb find function with string comparison does not work as expected - find

as you can see in the image i am querying a date string d_lastOpened against d_updated. The goal is to show all that where updated after lastOpened, that means d_lastOpened <= d_updated. Why is the 2. entry of the search result shown when it clearly does not fit that criteria?
i tried swapping fields around and using $gte but that does not work at all, which is logical.

You're making a string comparison between the strings "d_updated" and the values for d_lastOpened, starting with "2022".
"2022" < "d", therefore the "$lte" comparison returns the two results, but "$gte" fails.

Related

MongoDB does not return a field

It must be a silly mistake but I can't find it.
When I run db.getCollection('communes').findOne({}),
I obtain:
{
"_id" : ObjectId("59b851a19db72301ae771c57"),
"COMMUNE" : "ALAA6",
"LIBGEO" : "ROHRBACH",
"PAYS" : "Allemagne"
}
which is fine.
But when I run db.getCollection('communes').findOne({COMMUNE: "ALAA6"}), it returns nothing!
For strange reasons, filtering on other fields work, so when I run db.getCollection('communes').findOne({LIBGEO: "ROHRBACH"}), it returns the result. Same thing filtering on "PAYS".
Adding quotes around COMMUNE, i.e. running db.getCollection('communes').findOne({"COMMUNE": "ALAA6"}) or using find instead of findOne doesn't change anything.
Any idea?
Ok, my fault. The collection has been created from an Excel export, and it seems the first column contains a strange character. Querying from the Robo3T client did not show it, but querying from Python returns:
{'LIBGEO': 'ROHRBACH',
'PAYS': 'Allemagne',
'_id': ObjectId('59b851a19db72301ae771c57'),
'\ufeffCOMMUNE': 'ALAA6'}
so obviously the \ufeffchar before COMMUNEshould be removed...

significance of $ and "" in mongodb

I am learning MongoDB. Getting confused on usage of "$"
I have collection as below schema:
{
_id: 1,
"name": "test",
"city": "gr",
"sector": "IT",
"salary":1000
}
I find below output on executing below query:
Query Result
db.user.find({salary:2000}); Works
db.user.find({$salary:2000}); does not work(unknown top level operator: $salary)
db.user.aggregate({$group:{_id:null,avg:{$avg:"$salary"}}}); Works
db.user.aggregate({$group:{_id:null,avg:{$avg:$salary}}}); does not work($salary is not defined)
db.user.aggregate({$group:{_id:null,avg:{$avg:"salary"}}}); gives wrong output.
Can anyone please explain,what is the syntactical significance of "" and $ in mongoDB.
Hi lets look at these queries
1- db.user.find({salary:2000});
2- db.user.find({$salary:2000});
Take a look at this for find.
According to this find takes {field: value}, your first query works because salary is valid field.
Your second query doesn't work becuase there is no field $salary
3- db.user.aggregate({$group:{_id:null,avg:{$avg:"$salary"}}});
4- db.user.aggregate({$group:{_id:null,avg:{$avg:$salary}}});
5- db.user.aggregate({$group:{_id:null,avg:{$avg:"salary"}}});
For aggregation, lets take a look at this $avg.
Here it says that $avg takes {$avg: expression}. So you are actually keeping expression over there not a field.
Now take a look at this for expression.
Expression can be field paths and system variables, literals, expression objects, and expression operators.
Query numbers 3,4,5 aren't expression objects or expression operators. So lets eliminate these options.
Now lets take a look at $literal.
It states that literals can be of any type, however MongoDB parses literals that start with a dollar sign as a path to a field.
Finally take a look at Field Path and System variables.
It states "To specify a field path, use a string that prefixes with a dollar sign $ ... For example, "$user" to specify the field path for the user field or "$user.name" to specify the field path to "user.name" field."
That means you are specifying $salary as path to the field in $avg:"$salary" and query number 3 works.
Query number 4 doesn't work because $salary is an invalid expression.
This should explain the significance of ""
Query number 5 is not working because again it doesn't find any field to average on. Though it works because its a valid query it simply returns null.
You could have had
db.user.aggregate({$group:{_id:null,avg:{$avg:"some_non_existent_field"}}});
And the query will still run fine but you will get null for your results.
I hope this helps, this was a lot of fun to gather.

MongoDB - find if a field value is contained in a given string

Is it possible to query documents where a specific field is contained in a given string?
for example if I have these documents:
{a: 'test blabla'},
{a: 'test not'}
I would like to find all documents that field a is fully included in the string "test blabla test", so only the first document would be returned.
I know I can do it with aggregation using $indexOfCP and it is also possible with $where and mapReduce. I was wandering if it's possible to do it in find query using the standard MongoDB operators (e.g., $gt, $in).
thanks.
I can think of 2 ways you could do this:
Option 1
Using $where:
db.someCol.find( { $where: function() { return "test blabla test".indexOf(this.a) > -1; } }
Explained: Find all documents whose value of field "a" is found WITHIN some given string.
This approach is universal, as you can run any code you like, but less recommended from a performance perspective. For instance, it cannot take advantage of indexes. Read full $where considerations here: https://docs.mongodb.com/manual/reference/operator/query/where/#considerations
Option 2
Using regex matching trickery, ONLY under certain circumstances; below is an example that only works with matching that the field value is found as a starting substring of the given string:
db.someCol.find( { a : /^(t(e(s(t( (b(l(a(b(l(a( (t(e(s(t)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?)?$/ } )
Explained: Break up the components of your "should-be-contained-within" string and match against all sub-possibilities of that with regex.
For your case, this option is pretty much insane, but it's worth noting as there may be specific cases (such as limited namespace matching), where you would not have to break up each letter, but some very finite set of predetermined parts. And in that case, this option could still make use of indexes, and not suffer the $where performance pentalties (as long as the complexity of the regex doesn't outweigh that benefit :)
You can use regex to search .
db.company.findOne({"companyname" : {$regex : ".*hello.*"}});
If you are using Mongo v3.6+, you can use $expr.
As you mentioned $indexOfCP can be used to get index, here it will be
{
"$expr": {
{$ne : [{$indexOfCP: ["test blabla test", "$a"]}, -1]}
}
}
The field name should be prefixed with a dollar sign ($), as $expr allows filters from aggregation pipeline.

MongoDB: Using *NOT-dot* notation in sort

I'm having an issue with the Mongo sort on nested collection and Google search didn't help:
Dot notation works (returns first element from sorted collection):
db.myCollection.find().sort({ 'comments.Comment' : -1 })[0]
Array (Not-dot) notation doesn't work (always returns first element from un-sorted collection):
db.myCollection.find().sort({ "comments['Comment']" : -1 })[0]
For some business reasons I would like my app to be dynamic and handle spaces/pluses/and few more un-standard characters as the keys in the documents,
So far I was ok with it but sort always returns first (unordered) result if it can't understand the key which I want to sort on.
Simply put:
"For some business reasons I would like my app to be dynamic and handle spaces/pluses/and few more un-standard characters as the keys in the documents"
Yeah, well bad luck it's not valid JSON notation, it may be JavaScript notation but that doesn't mean it's valid JSON. And the BSON spec derives from this fact.
You have dot (.) notation and that is it. So basically your condition is parsed as "invalid" and is ignored, hence no sorting is done how you expect.
Feel free to raise a JIRA issue with MongoDB if you believe this is important.

Mongodb $strcasecmp. Strange behaviour when the field content has dollar signs

I'm triying to compare two strings on MongoDB Aggregation Framework. This is the query I'm using:
db.people.aggregate({
$project:{
name:1,
balance:1,
compareBalance:{$strcasecmp:["$balance","$2,500.00"]}
}
});
My problem is that each "$balance" field has a dollar sign at the begining of the string, and the results returned by the query seem to be incorrect. For example:
{
"_id" : ObjectId("5257e2e7834a87e7ea509665"),
"balance" : "$1,416.00",
"name" : "Houston Monroe",
"compareBalance" : 1
}
As you can see the results, the field comparision is 1, but it should be -1 because $2,500.00 is higher than $1,416.00. In fact, all comparisions has a value of 1.
There is a workaround by using $substr to remove the dollar sign at the beginning of all fields, but I want to know who is doing this wrong, MongoDB or me.
Thanks in advance.
It sounds like you are trying to use the "balance" field as a numeric, for example might want to compare $10 to $100.
The best way to do this is to store the actual value, and add the formatting, the $ the , etc when displaying to the user.
So, you would have - balance: 2500
Slightly unrelated...
Not sure if you are doing much calculation on the value, but using binary floating point numbers for currency is a bad idea (can't accurately represent all numbers), so, it's often better to store an integer with the cents (or if high precision is required, an integer for hundredths of cents)
This could give: balanceCents: 250000 or balanceFourDec: 25000000
Then you can use $gt $lt and arithmetic
The $ is used as a field reference operator. So, the aggregation pipeline is trying to do a comparison between a field called "$balance" and "$2,500.00":
{
"balance": "$5,000.00",
"2,500.00": undefined
}
Of course, that's not what you are looking for.
You shouldn't start with the $ in the data. Also, unless you've got fixed length strings, sorting and comparisons isn't going to work the way you would expect if you're trying to store numbers as strings. If you're just doing this as an example, I'd suggest you use the actual math operators for numbers, and leave $strcasecmp to actual strings.
you can use the { $literal: < value > } pipeline operator to ignore the cash sign.
https://docs.mongodb.com/manual/reference/operator/aggregation/literal/