How to perform aggregate query with where condition - mongodb

I have this MongoDB query:
var array=[]; //some string values
collection.aggregate(
{ $match: { '_id': { $in : array } } }
)
But this is not returning any results. How do I perform this?

As noted in the comments, your array variable is an array of hex string values ex :["57f36e94517f72bc09ee761e"] and for mongo shell, you need to first cast those string values to ObjectIds. Use the JavaScript map()
method to accomplish the casting in a list.
For example:
mongo shell
var array = ["585808969e39db5196444c07", "585808969e39db5196444c06"];
var ids = array.map(function(id){ return ObjectId(id); });
which you can then query using the aggregate function as in the following
db.collection.aggregate([
{ "$match": { "_id": { "$in" : ids } } }
])
The above is essentially the same as
db.collection.find({ "_id": { "$in": ids } })
Node.js
var {ObjectId} = require('mongodb'); // or ObjectID
var ids = array.map(id => ObjectId.isValid(id) ? new ObjectId(id) : null;);

Related

mongodb query map by key

I have the following structure in mongodb:
person:
{
"1" [personId] : ["some_text", "some_text"],
"2" [personId] : ["some_text", "some_text"],
"3" [personId] : ["some_text", "some_text"]
}
I would like to query a person map structure and get only values when personid (key) is between 1 to 2
I try to use $elemMatch but its not a good idea because I would like query by a dynamic range.
I use map strucute becuase I have another process that insert person data dynamically by person id.
Is there any way to filter map structure data by key?
Thanks
The code is not actually tested. But this might work:
const searchParams = [
{ $elemMatch: { fieldA: "val1", fieldB: "val2" } },
{ $elemMatch: { fieldC: "val3", fieldD: "val4" } },
]
const results = await yourDB.find({
person: {
$in: searchParam
}
})
The elements of searchParams can be dynamically generated based on your need.
searchParams.psuh({ $elemMatch: { fieldX: "val_x", fieldZ: "val_z })
You need an to run an aggregate operation where you can convert the hash map into an array of key value documents, filter the array based on the above condition and convert the filtered array back to the hash map.
Take for instance the following operation, it uses the $addFields pipeline step to do the above operations with the aid of the $objectToArray, $filter and $arrayToObject operators:
db.collection.aggregate([
{ '$addFields': {
'person': {
'$arrayToObject': {
'$filter': {
'input': { '$objectToArray': '$person' },
'cond': {
'$in': ['$$this.k', ['1', '2']]
}
}
}
}
} }
])

Query documents with condition on array field in mongoose

I have a mongoose schema like this:
var schema = new Schema({
expenses: [{name: String, cost: number}]
});
schema.virtual('totalCost').get(function() {
let totalCost = 0;
this.expenses.forEach((expense)=> {
totalCost += expense.cost;
})
return totalCost;
})
Now I want to query all trips that have totalCost between minCost and maxCost. Is there any way I can do that? I tried $where but I can't pass minCost, maxCost to the function.
You can't query against a Mongoose virtual property as they only exist in the Mongoose model representation of documents, not in MongoDB itself where the query should be executed against.
You can however run an aggregation query that calculates the total cost and then use the $match pipeline to query the documents. The following example shows this approach:
Trip.aggregate([
{ "$unwind": "$expenses" },
{
"$group": {
"_id": "$_id",
"totalCost": { "$sum": "$expenses.cost" },
"expenses": { "$push": "$expenses" }
}
},
{
"$match": {
"totalCost": {
"$gte": minCost,
"$lte": maxCost
}
}
}
]).exec(callback);
I think $where is the only way, you can achieve that but $where is costly.
I am not sure what are the options in mongoose to use $where but it would be something like below
var minCost=1000;
var maxCost = 10000;
query.$where(function () {
var cost=0;
for(var i in this.expenses){cost+=this.expenses[i].cost}
if(cost>minCost && cost<maxCost){return true;}
})
Here is the link
Another way is we can pass the javascript as a string in $where clause
var minCost=1000;
var maxCost = 10000;
var func = 'var cost=0;for(var i in this.expenses{cost+=this.expenses[i].cost}if(cost>'+minCost+' && cost<'+maxCost+'){return true;}'
query.$where(func);

Return an array from Model.findOne?

I have a query which retuns an array of documents as a promise (.exec).
Further I have a (promised) function which also returns an array. Both are combined in a Promise.all.
Now I want to move the .find to a .findOne to speed up the filter. But with findOne I would get no array back. So I decided to use .find().limit(1)
My question is if this is a valid approach, instead of the use of .findOne and if not: Is there a simple way to return the result of findOne as an array? Maybe with .lean ?
var query = Model.find({ $and: [ { _id: id },
{ $or: [ { owner: userID },
{ isPublic: true } ]}
]}).limit(1);
Promise.all([query.exec(), this._sources(user)]).then((doc: Array<any>) => {....}
findOne returns an object, not an array. You can create an array with the result like this: return [obj]. I'm not sure but you can try this one
var queryResult = Model.findOne({ $and: [ { _id: id },
{ $or: [ { owner: userID },{ isPublic: true } ]}]})
.exec(function(err, data){
if(err) return [];
return [data];
});
Promise.all([queryResult, this._sources(user)]).then

Pluck id's from mongo query result

I have the following query on mongo console
db.photos.find({'creation_date': {$gte: <somedate>)}}).
Is there a way to pluck the id's from query result just by using mongo shell ?
Try using the map() cursor method
var ids = db.photos.find({'creation_date': { '$gte': <somedate>) } }, {'_id': 1})
.map(function (doc){ return doc._id; })
You can also use the distinct() method as
var ids = db.photos.distinct('_id', {'creation_date': { '$gte': <somedate>) } })
or with the toArray() cursor method on aggregate() as
var ids = db.photos.aggregate([
{ '$match': {'creation_date': { '$gte': <somedate>) } } }
{ '$group': { '_id': 0, 'ids': { '$push': '$_id' } } }
]).toArray()[0].ids
MongoDb provides limit fields from query results
See more about in below link
http://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/
db.photos.find({'creation_date': {$gte: )},{"_id":1}});
returns
{
"_id":1
}
{
"-id":2
}
...
You can use distinct instead of find:
collection.distinct('_id', {'creation_date': some_date})

How can I search for all documents with _id in an array?

I want to search for all documents with an _id that is in an array of id's. Here is what I have so far, but it is returning nothing:
var myArray = [53950fe210bcef043aa6e135, 5394f5be2f6953083908db47];
User.find(
{_id: { $in : myArray }},
null,
{},
function (err, data) {
if (!err){
return res.json(data);
}
}
);
What am I doing wrong?