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

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

Related

How does mongodb use an index to count documents?

According to docs, db.collection.countDocuments() wraps this:
db.collection.aggregate([
{ $match: <query> },
{ $group: { _id: null, n: { $sum: 1 } } }
])
Even if there is an index, all of the matched docs will be passed into the $group to be counted, no?
If not, how is mongodb able to count the docs without processing all matching docs?
The MongoDB query planner can make some optimizations.
In that sample aggregation, it can see that no fields are required except for the ones referenced in <query>, so it can add an implicit $project stage to select only those fields.
If those fields and the _id are all included in a single index, there is no need to fetch the documents to execute that query, all the necessary information is available from the index.

Drop _id in MONGO return [duplicate]

Can I somehow add custom field with static (not computed) value?
I want to prepare objects before send and I need to remove some fields with internal information and add field with some entity ID.
For example I have collection "test" with objects like this
{_id: ObjectId(...), data: {...}}
And I need to convert it to
{data: {...}, entity_id: 54}
So how can I add entity_id: 54 without looping over result in my code?
db.test.aggregate({ $project: {_id: 0, data: 1, entity_id: ? } })
Thanks
Note that $literal was implemented in Mongo 2.6.
So now you can simply write:
db.test.aggregate(
{$project: {_id: 0, data: 1, entity_id: {$literal: 54}}})
See $literal.
edit as of 2.6 the $literal expression exists so you don't have to use the workaround now.
Original answer: I know this may sound really dumb, but you can use a "no-op" expression to "compute" what you need.
Example:
db.test.aggregate( { $project : {_id:0, data:1, entity_id: {$add: [54]} } } )
There was a proposed $literal operator for exactly this use case but it hasn't been implemented yet, you can vote for it here.

How can I express `find` conditions in MongoDB accessing document's values?

For example, let's put the case I want all documents inside a collection which are inside a range, whose maximum value is inside the document itself:
myDocument {
qty: Number,
maxValue: Number,
}
db.collection.find( { field: { $gt: 0, $lt: maxValue } } );
Is it possible to do something like that in MongoDB?
Yes you can, using $cmp and aggregation https://docs.mongodb.com/v3.4/reference/operator/aggregation/cmp/
db.col.aggregate([
{$project: {compareResult: {$cmp: ['$field','$maxValue']}}},
{$match: {compareResult: -1, field: {$gt: 0}}}
])
First, run this command to get max value of "maxValue" field
db.collection.find({},{maxValue:1}).sort({"maxValue":-1}).limit(1)
Let's assume max value is 3000.
Then run this
db.collection.find({"maxValue":{"$gte":0 ,"$lte":3000}})

Indexes with $in or $or

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"]}});

MongoDB: aggregate $project add field with static value

Can I somehow add custom field with static (not computed) value?
I want to prepare objects before send and I need to remove some fields with internal information and add field with some entity ID.
For example I have collection "test" with objects like this
{_id: ObjectId(...), data: {...}}
And I need to convert it to
{data: {...}, entity_id: 54}
So how can I add entity_id: 54 without looping over result in my code?
db.test.aggregate({ $project: {_id: 0, data: 1, entity_id: ? } })
Thanks
Note that $literal was implemented in Mongo 2.6.
So now you can simply write:
db.test.aggregate(
{$project: {_id: 0, data: 1, entity_id: {$literal: 54}}})
See $literal.
edit as of 2.6 the $literal expression exists so you don't have to use the workaround now.
Original answer: I know this may sound really dumb, but you can use a "no-op" expression to "compute" what you need.
Example:
db.test.aggregate( { $project : {_id:0, data:1, entity_id: {$add: [54]} } } )
There was a proposed $literal operator for exactly this use case but it hasn't been implemented yet, you can vote for it here.