Indexes with $in or $or - mongodb

My document structure is something like this
{
_id: "id1",
field1: "val1",
field2: "val2",
outcome: "ABC"
}
I have created index on outcome field. I have to find all documents with {outcome:"ABC"} or {outcome:"XYZ"} only. There is no major difference in query execution time if i use $or or $in. e.g
db.coll.find({$or:[{outcome:"ABC"},{outcome:"XYZ"}]});
db.coll.find({outcome:{$in:["ABC","XYZ"]}});
Which operator should i use $or or $in in this case? And why? Any help would be appreciated.

MongoDB docs
When using $or with <expressions> that are equality checks for the value of the same field, use the $in operator instead of the $or operator.
For example, to select all documents in the inventory collection where the quantity field value equals either 20 or 50, use the $in operator:
db.inventory.find ( { quantity: { $in: [20, 50] } } )
So in your case it is better to use
db.coll.find({outcome:{$in:["ABC","XYZ"]}});

Related

How to $inc a field by another field in the same document?

How do I use the value of another field in $inc to define how much to increase?
Example-
Some doc
{_id: obi, length: 256, delta: 6}
Here, I want to increase the length by delta increment.
Pseudocode would be
db.collection.update({}, $inc: {length: $delta});
Thanks for helping...
Simple update operation can't allow to use internal fields in another fields, either its any of the operators,
For the solution you can use update with aggregation pipeline starting from MongoDB 4.2,
use $add/$sum any operator from both to sum the both fields number
db.collection.update({},
[{
$set: {
length: {
$add: ["$length", "$delta"]
}
}
}]
)
Playground

MongoDB: find document whose subdocument contains a given value

Given is a Document like the following
{
"type" : "sometype",
"title" : "sometitle",
"references":{
"1": "someref",
"2": "otherref",
"3": ""
}
}
How can I find all documents which have the reference someref set in the subdocument references?
A simple find({references: "someref"}) doesn't work because references is not a valid array.
Document structure is not ideal for this kind of queries but you can use aggregation with $objectToArray operator:
db.collection.aggregate([
{$addFields: {refs: {$objectToArray: "$references"}}},
{$match: {"refs.v": "someref"}},
{$project:{refs: 0}}
])
If the number of subdocument fields you are looking into is small, then you can simply filter your collection using $or
db.collection.find(
{ $or: [
{"references.1": "someref"},
{"references.2": "someref"},
{"references.3": "someref"}
]} )

The $in operator inside $project, $match or find()

I have a find query that uses $in to check whether the specified array is contained within the collection string array:
db.Doc.find({ tags: { '$in': ['tag1','tag2'] } })
I am in the process of refactoring this query to use the aggregation framework, but I can't find the equivalent $in comparison operator at the $project or $match aggregation stages.
Is it possible to use the $in comparison operator at the $project or $match stages of an aggregation query.
To answer your question: yes, but not as you would expect. It is possible to use the $in operator at the $project or $match stages of an aggregation query, but the usage and the purpose aren't quite the same in each.
There are two extremely different types of the "same" $in operator (making a semantic confusion):
Non-aggregational $in: Usually narrows down the results, like a filter. It has no way to add information to the result set, if it doesn't match. Can be used both within find() collection method and inside the aggregational (quite confusing semantic ah?) $match.
Aggregational $in: Usually adds boolean information to the result set, can be used as a logic expression inside $cond, and might also remove some results when is used with $redact. Can be used in $project, $addFields, etc. (but cannot (!) be used within find() or $match). The structure is: { $in: [ <needle expression>, <array haystack expression> ] }, and all of this grey line becomes either true or false (I used PHP's documentation's in_array needle-heystack semantic to better explain). So, { $in [ 'foo', [ 'foo', 'bar', 'baz' ] ] } is true because foo is inside the array.
However, in the previous non-aggregational $in, the { maybeFooField: { $in: [ 'foo', 'bar', 'baz' ] } } structure query simply narrows down the result set, and it doesn't result in a boolean true or false.
Going back to your refactoring, the question is what are your intended results? Why did you switch to the aggregation framework from the beginning?
If you only want to narrow down or filter out the result set, and then use some other aggregation computations, use the simple non-aggregational $in operator.
db.Doc.aggregate([
{ $match: { tags: {$in: ['tag1','tag2'] } } } // non-aggregational $in
])
However, if you want to add information based on the existence or absence of certain tags, use the aggregational $in operator.
db.Doc.aggregate([
{ $project: { hasAnyTag: {$in: [$tags, ['tag1', 'tag2'] ] } } } // aggregational $in
])
Note, you have more aggregational operators to play with arrays, like: $setIntersection and $setIsSubset.
The query: db.Doc.find({ tags: { '$in': ['tag1','tag2'] } }) is equivalent to:
db.Doc.aggregate([
{$match:{tags: {$in: ['tag1','tag2'] }}}
])
And when u use $in at projection like below:
db.Doc.aggregate([
{$project:{tags: {$in: ['tag1','tag2'] }}}
])
Result will be tags:true or tags:false depending upon whether there's match or not.

How to find specific key in MongoDB?

I have to find all the documents which include "p396:branchCode" as key in MongoDB.Value does not matter,can be anything.I tried using
{"p396:branchCode": new RegExp(".*")}
in MongoVUE but i found nothing.
My db is very nested and branchCode has superkey "p396:checkTellersEApproveStatus"
Your key is nested under a super-key, so you need to use the dot-operator:
{"p396:checkTellersEApproveStatus.p396:branchCode": {$exists: true}}
This assumes p396:branchCode is always under p396:checkTellersEApproveStatus. When that's not the case, you have a problem, because MongoDB does not allow to do queries for unknown keys. When the number of possible super-keys is low, you could query for all of them with the $or-operator. When not, then your only option is to refactor your objects to arrays. To give an example, a structure like this:
properties: {
prop1: "value1",
prop2: "value2",
prop3: "value3"
}
would be far easier to query for values under arbitrary keys when made to look like this:
properties: [
{ key: "prop1", value:"value1"} ,
{ key: "prop2", value:"value2"},
{ key: "prop3", value:"value3"}
]
because you could just do db.collection.find({"properties.value":"value2"})
If you are actually "mixing types then that probably is not a good thing. But if all you care about is that the field $exists then that is the operator to use:
db.collection.find({
"p396:checkTellersApproveStatus.p396:branchCode": { "$exists": true }
})
If the values are actuall "all" numeric and you have an expected "range" then use $gt and $lt operators instead. This allows an "index" on the field to be used. And a "sparse" index where this was not present in all documents would improve performance:
db.collection.find({
"p396:checkTellersApproveStatus.p396:branchCode": {
"$gt": 0, "$lt": 99999
}
})
In all cases, this is the "child" of the parent "p396:checkTellersApproveStatus", so you use "not notation" to acess the full path to the property.
Sounds like you want to use the $exists operator.
{'p396:branchCode': {$exists: true}}
This assumes this query is part of the path:
{ 'p396:checkTellersApproveStatus': {'p396:branchCode': {$exists: true}}}
Which can be shortened to:
{ 'p396:checkTellersApproveStatus.p396:branchCode': {$exists: true}}

Mongodb : How to find documents in which fields match an ObjectId or a string?

I have some documents in a collection in Mongodb :
{_id : ObjectId('533af69b923967ac1801e113'), fKey : '533aeb09ebef89282c6cc478', ... }
{_id : ObjectId('5343bd1e2305566008434afc'), fKey : ObjectId('5343bd1e2305566008434afc'), ...} }
As you can see my field fkey can be set by a string or an ObjectId.
I would like to get all documents which match '533aeb09ebef89282c6cc478' or ObjectId('5343bd1e2305566008434afc').
But if i run :
db.mycollection.find({fkey : '533aeb09ebef89282c6cc478'})
I only get the first document of the collection.
Is there a way to configure Mongodb in order to get all documents which match the request without checking the type ?
Thanks for your help.
Pierre
There are two options for you here.
You could use mongo's $or operator:
db.mycollection.find({
$or: [
{ fKey: '533aeb09ebef89282c6cc478' },
{ fKey: ObjectId( '533aeb09ebef89282c6cc478' ) }
]
})
The $or operator performs a logical OR operation on an array of two or more <expressions> and selects the documents that satisfy at least one of the <expressions>.
You could also use the $in operator:
db.mycollection.find({
fKey: {
"$in": [ '533aeb09ebef89282c6cc478', ObjectId( '533aeb09ebef89282c6cc478' ) ]
}
})
The $in operator selects the documents where the value of a field equals any value in the specified array.
It sounds to me like these inconsistencies are not meant to be there. I recommend going through your code and data pipelines and figure out who/what is inserting the fKey value with an unknown datatype.