how to pass multiple element in $match(aggregation) in MongoDB - mongodb

db.tst_col.aggregate( { $match : { abc : {1,2,3} }})
How to check for the multiple values for the abc, like i have to check the value for abc from 1 to 20 in one statement
How to do that?

You can use any query arguments in the aggregation framework like you can with normal queries, so you can do:
db.tst_col.aggregate( { $match: { abc: { $gte: 1, $lte: 20 } } } );
If you don't want a range, you can do it as follows:
db.tst_col.aggregate( { $match: { abc: { $in: [ 1, 4, 12, 17, 20 ] } } } );

Related

How to search in MongoDB an element depending on the previous one?

I'm having to deal with a query that is kind of strange. I'm creating an app for boat tracking: I have a collections of documents with the timestamp and the Port ID where it was the board at that moment.
After sorting all the documents of this collection by the timestamp descending, I need to grab the elements that have the same Port ID in that range of time.
For example:
timestamp | port_id
2021-11-10T23:00:00.000Z | 1
2021-11-10T22:00:00.000Z | 1
2021-11-10T21:00:00.000Z | 1
2021-11-10T20:00:00.000Z | 2
2021-11-10T19:00:00.000Z | 2
2021-11-10T18:00:00.000Z | 2
2021-11-10T17:00:00.000Z | 1
2021-11-10T16:00:00.000Z | 1
2021-11-10T15:00:00.000Z | 1
Having this data (sorted by timestamp), I would have to grab the first 3 documents. The way I'm doing this now, is grabbing 2000 documents and implementing a filter function in the application level.
Another approch would be grabbing the first element, and then filtering by that port id, but that returns me 6 elements, not the first 3.
Do you know any way to perform a query like this in Mongo? Thanks!
Use $setWindowFields
db.collection.aggregate([
{
$setWindowFields: {
partitionBy: "",
sortBy: { timestamp: -1 },
output: {
c: {
$shift: {
output: "$port_id",
by: -1,
default: "Not available"
}
}
}
}
},
{
$set: {
c: {
$cond: {
if: { $eq: [ "$port_id", "$c" ] },
then: 0,
else: 1
}
}
}
},
{
$setWindowFields: {
partitionBy: "",
sortBy: { timestamp: -1 },
output: {
c: {
$sum: "$c",
window: { documents: [ "unbounded", "current" ] }
}
}
}
},
{
$match: { c: 1 }
},
{
$unset: "c"
}
])
mongoplayground

MongoQuery to update document using addition

I have the following document in student collection:
{
"uid": 1,
"eng": 70
}
Now I want to add 10 into eng field and want result 80. to do this I am using following query:
db.getCollection('student').aggregate([{$match:{uid:1}},{$set:{eng:{$sum:10}}}])
but it is not working. SO how can add any number in the field to the required output? is any addition query in MongoDB. help me here
I suggest using the $inc operator here:
db.getCollection('student').update(
{ uid: 1 },
{ $inc: { eng: 10 } }
)
SOLUTION #1: Set sum to the same field eng.
db.student.aggregate([
{ $match: { uid: 1 } },
{
$set: {
eng: { $add: ["$eng", 10] } // $sum: ["$eng", 10] Also works;)
}
}
])
Output:
{
"_id" : ObjectId("6065f94abb72032a689ed61d"),
"uid" : 1,
"eng" : 80
}
SOLUTION #2: Set sum to a different field result.
Using $addFields add result filed.
Using $add add 10 to eng and store it in result.
db.student.aggregate([
{ $match: { uid: 1 } },
{
$addFields: {
result: { $add: ["$eng", 10] }
}
}
])
Output:
{
"_id" : ObjectId("6065f94abb72032a689ed61d"),
"uid" : 1,
"eng" : 70,
"result" : 80
}

MongoDB - Autocomplete - Get all words starting with X

I have a collection (users) with the following structure:
{
propA: {
words: ["i", "have", "an","important", "question"]
}
}
I want to get autocomplete options from the db for some input in my website.
So first, i think that i need to create an index for propA.words.
Maybe something like this(?):
db.users.createIndex({ "propA.words" : 1 })
Second, how can i query this index to get all the words starting with X?
For example, for the string "i", the query will retrieve ["i", "important"].
Thanks!
EDIT:
This is the collection:
{
propA: {
words: ["aa","bb","cc","dd"]
}
}
{
propA: {
words: ["ab"]
}
}
{
propA: {
words: []
}
}
{
propB: []
}
Now, i want a query to get all the words that starts with "a".
The query should return ["aa","ab"] on the above collection.
I want the query to use only the index so the search will be efficient.
You can use this aggregation, which iterates over the words array and matches the regex search string.
db.collection.aggregate( [
{
$addFields: {
matches: {
$filter: {
input: "$propA.words",
as: "w",
cond: {
$regexMatch: { input: "$$w" , regex: "^i" }
}
}
}
}
}
] )
The output:
{
"_id" : 1,
"propA" : {
"words" : [
"i",
"have",
"an",
"important",
"question"
]
},
"matches" : [
"i",
"important"
]
}
[ EDIT ADD ]
Now, i want a query to get all the words that starts with "a". The
query should return ["aa","ab"] on the above collection. I want the
query to use only the index so the search will be efficient.
The aggregation:
db.collection.aggregate( [
{
$match: { "propA.words": { $regex: "^a" } }
},
{
$unwind: "$propA.words"
},
{
$group: {
_id: null,
matchedWords: {
$addToSet: {
$cond: [ { $regexMatch: { input: "$propA.words", regex: "^a" } },
"$propA.words",
"$DUMMY" ]
}
}
}
},
{
$project: { _id: 0 }
}
] )
The result:
{ "matchedWords" : [ "ab", "aa" ] }
Index usage:
The index is created on the collection as follows:
db.collection.createIndex( { "propA.words": 1 } )
You can verify the index usage on the aggregation's $match stage by applying the explain and generating a query plan. For example:
db.collection.explain("executionStats").aggregate( [ ... ] )
yes you make an index on the field, which is an array. then use regex query - the symbol ^ for 'starts with'... an index on an array field can create a big load... but your query being a 'start-with' is an efficient design....

How to use '$let' in MongoDB Aggregation Query in Scala?

I am trying to write a mongoDB aggregation query in Scala.
How do I write Scala code to use "$let" in '$project' stage?
I am wondering if Variable should be used. Not sure how?
'$project': {
'myprojitem' :{
'$let': {
'vars' : { 'myVariable1': { '$or': [...] } }
'in' : {
'$cond': [
'$$myVariable1',
{ ... },
{ ... },
]
}
}
I figured out the answer. Hopefully it helps someone.
val doc : Document = Document("{
'$let': {
'vars' : { 'myVariable1': { '$or': [...] } },
'in' : { '$cond': ['$$myVariable1',{ ... },{ ... } ]
}
}")
var pipeline = mutable.Buffer[Bson]()
pipeline += Aggregates.project(Projections.fields(
Projections.computed("myprojitem",doc)
))
Basically, every { name : expression } can be written as :
Document("name" -> expression)
Or
Document( "{name : expression}")
$let is used to bind variables together to a results obj. The syntax follows the rule:
{
$let:
{
vars: { <var1>: <expression>},
in: <expression>
}
}
for mere details you should take a look at $let (aggregation) definition from mongodb manual
Here is a text book example just to make more sense:
Consider the following data:
{ _id: 1, price: 10, tax: 0.50, applyDiscount: true }
{ _id: 2, price: 10, tax: 0.25, applyDiscount: false }
And imagine that we want to generate a result for the finalTotal in a way that:
Where Disc = 10% if applyDiscount: true and 0 otherwise.
So we need now to create the aggregation on the data to construct this equation. So we can get a results like:
{ _id: 1, finalTotal: 9.45 }
{ _id: 2, finalTotal: 10.25 }
We can do this by doing:
$project: {
finalTotal: {
$let: {
vars: {
total: { $add: [ '$price', '$tax' ] },
discounted: { $cond: { if: '$applyDiscount', then: (0.9, else: 1 } }
},
in: { $multiply: [ "$$total", "$$discounted" ] }
}
}
}
We can break this down:
Step 1. adding price to tax together to a variable called total
total: { $add: [ '$price', '$tax' ] },
Step 2. transforming the condition in numbers (variable discounted)
discounted: { $cond: { if: '$applyDiscount', then: 0.9, else: 1 } }
Step 3. performing the operation $multiply operation between the constructed $$total and $$discounted
in: { $multiply: [ "$$total", "$$discounted" ] }

confusion about $and operation

Following MongoDB documentation example seems to be wrong.
Any suggestion?
a== 1 and a >5 will never match any document.
Link
db.foo.find( { $and: [ { a: 1 }, { a: { $gt: 5 } } ] } )
In the above example documents with an element of a having a value of a equal to 1 and a value of a greater than 5 will be returned
You are missing an import line in the example:
db.foo.insert( { a: [ 1, 10 ] } )
db.foo.find( { $and: [ { a: 1 }, { a: { $gt: 5 } } ] } )
The insert will give you a record looking like the following:
{"a" : [1, 10] ,
"_id" : "497ce4051ca9ca6d3efca323"}
So the find will return any result where a == 1 and a also has a value greater than 5. In this case, a can be two values: http://www.mongodb.org/display/DOCS/Multikeys
The a is 1, and at the same time 10. So that is why this query would return this result.