MongoDB update where multiple conditions - mongodb

I am attempting to update information on one of my fields where two different conditions are met. I don't know if this is the right idea on how to do it, but guidance would be appreciated. I am met with the error of: "unknown top level operator: $eq"
db.shop.update({"$and":[{"item.name":"Milk"}, {"$eq":{"item.price":2.80}}]}, {"$set": {"item.expiry":"21/10/19"}});

You can use $and as
db.shop.update(
{"$and":[{"$eq":["item.name","Milk"]}, {"$eq":["item.price",2.80]}]},
{"$set": {"item.expiry":"21/10/19"}}
)
but it is equivalent to below and will be faster as expression takes time to compute
db.shop.update(
{"item.name":"Milk","item.price":2.80},
{"$set": {"item.expiry":"21/10/19"}}
)

Remove $eq and $and and just use the following query.
db
.shop
.update({
"item.name": "Milk",
"item.price": 2.80
}, {
"$set": {
"item.expiry": "21/10/19"
}
});

Related

How to write a mongo query that returns fields with the expected results?

For instance I am trying to bring up the organization ids that are tagged to multiple countries in db.
db.collection.find({"Region":{$in:["CHINA","JAPAN","SOUTH_KOREA"]}})
this doesnot give me the results that they have all 3 countries in the same document. Obviously $where does not work which I can query to bring up the fields that have more than 1 country in it.
Trying this for 2 days and need your help.
Thanks in advance.
Use $all
The $all operator selects the documents where the value of a field is an array that contains all the specified elements.
db.collection.find({"Region":{ $all :["CHINA","JAPAN","SOUTH_KOREA"] } })
i hope this will go acording youre need's:
db.collection.find({
$and: [
{ Region: {$in: /\bCHINA\b/i} },
{ Region: {$in: /\bJAPAN\b/i} },
{ Region: {$in: /\bSOUTH_KOREA\b/i} }
]
})
If I'm understanding your question correctly, you are trying to match a document where the Region key is a list conataining all three countries.
db.collection.find({$and: [
{Region: {$in: ["CHINA"]}},
{Region: {$in: ["JAPAN"]}},
{Region: {$in: ["SOUTH_KOREA"]}}
])
If so, this should work for you.
These two queries worked in my case. They are as simple as they look like but somehow I missed them our after many trials I may have miswritten them. Anyways here is the solution to my question:
db.collection.find({region:{$size:3}})
db.collection.find({ "region.2":{$exists:true}})

how to do aggregate after doing createIndexex in mongodb?

I want to optimize my query as much as possible. So I found a method called "createIndexes". But I am not getting how to use it along with "aggregate".
db.createIndexes({age:1})
.then(_ => {
return db.aggregate(
[
{"$match":{"age":age}},
{"$group":{
_id: '$name',
hobby:{$addToSet:'$hobby'}
}},
{$project:{
_id:0,
name:'$_id',
hobbyCount:{$size:'$hobby'}
}}
]
})
I want to put the index in the age column and then want to do the aggregate operation but the indexing is not happening. Anyone any idea why this is not working?
createIndexes() is an one time operation. Once you call this method, the indexes will be built and all the subsequent queries will use the indexes whenever possible.
That said, createIndexes does not affect how you call normally aggregate.

getting the latest xx records with mongoose, How to order them?

I'm trying to get the last 20 records of user collection with mongoose:
User.find({'owner': req.params.id}).
sort(date:'-1').
limit(20).
exec(.....)
This works well, show the last 20 items.
But the items inside the array are sorted from the most recent to the oldest, Is there any way to reverse this with mongoose?
Thanks
You can certainly do this with an aggregation, such as this:
db.user.aggregate[(
{ $match : {"owner" : req.params.id}},
{ $sort : {"date" : -1}},
{ $limit : 20},
{ $sort : {"date" : 1}}
])
Notes on this aggregation:
The first three parts do the same job as the Find in your question
The fourth part applies a further sort, which re-orders the returned 20 records from oldest to most recent
I have written it in native MongoDB aggregation syntax; you will need to adjust the code to generate the same aggregation from Mongoose.
Update: I think this is not possible with a find() with cursor methods, because you would need two different sort() operations. But, MongoDB does not treat them as a sequence of independent operations; the docs give an example of methods written in one order — sort().limit() — being equivalent to the opposite order — limit().sort(), showing that the order cannot be relied upon as meaningful.
Find total and select only latest 20 , may be this is not effective way you found , but this will solve your problem.
User.count({'owner': req.params.id},function(err,count){
if(count){
var skipItem=count-20;
User.find({'owner': req.params.id}).
.skip(skipItem)
.limit(20)
.sort(date:'1').
exec(.....)
}
});
db.users.aggregate([
{ $match: {
'owner': req.params.id
}},
{ $unwind: '[arrayFieldName]' },
{ $sort: {
'[arrayFieldName]': -1/1,
'date':-1
}}
])

MongoDB: distinct tuples

Suppose to have a collection of MongoDB documents with the following structure:
{
id_str: "some_value",
text: "some_text",
some_field: "some_other_value"
}
I would like to filter such documents so as to obtain the ones with distinct text values.
I learned from the MongoDB documentation how to extract unique field values from a collection, using the distinct operation. Thus, by performing the following query:
db.myCollection.distinct("text")
I would obtain an array containing the distinct text values:
["first_distinct_text", "second_distinct_text",...]
However, this is not the result that i would like to obtain. Instead, I would like to have the following:
{ "id_str": "a_sample_of_id_having_first_distinct_text",
"text": "first_distinct_text"}
{ "id_str": "a_sample_of_id_having_second_distinct_text",
"text": "second_distinct_text"}
I am not sure if this can be done with a single query.
I found a similar question which, however, do not solve fully my problem.
Do you have any hint on how to solve this problem?
Thanks.
You should look into making an aggregate query using the $group stage, and probably using the $first operator.
Maybe something along the lines of:
db.myCollection.aggregate([{ $group : { _id : { text: "$text"},
text: { $first: "$id_str" }
}
}])
try:
db.myCollection.aggregate({$group: {_id: {'text': "$text", 'id_str': '$id_str'}}})
More information here: http://docs.mongodb.org/manual/reference/method/db.collection.aggregate/

is it possible to use "$where" in mongodb aggregation functions

I need to get the length of a string value in MongoDB using aggregation functions.
it works in
db.collection_name.find({"$where":"this.app_name.length===12"})
but when implanted to
db.collection_name.aggregate({$match:
{"$where":"this.app_name.length===12"}
},
{
$group :
{
_id : 1,
app_downloads : {$sum: "$app_downloads"}
}
}
);
I got this result:
failed: exception: $where is not allowed inside of a $match aggregation expression
The question is: is it possible to use $where in aggregation functions?
or is there any way of getting the length of a string value in aggregation function?
Thanks in advance
Eric
MongoDB doesn't support $where in aggregation pipeline and hope this will never happen, because JavaScript slows things down. Never the less, you still have options:
1) Мaintain additional field(e.g. app_name_len) than will store app_name length and query it, when needed.
2) You can try extremely slow MapReduce framework, where you allowed to write aggregations with JavaScript.
Today I had the same problem.
Mongodb doesn't support this.app_name.length, but you can do this condition with $regex - this is not very quick, but it still works.
{"app_name": { $regex: /^.{12}$/ }}
A simple way to achieve the behaviour expected of OP would be chaining up $expr with $strLenCP
db.collection.find({
$expr: {
$eq: [
12,
{
$strLenCP: "$app_name"
}
]
}
})
Mongo Playground