In searching through MongoDB data I've been able to query a collection based on whatever fields the user provides by adding any non-null field to a query object, which so far has covered all of my bases. But I've run into an issue with needing to add to it. Basically doing this for 10 fields:
let query = {};
let weekNumber = null;
if (req.params.weekNumber !== 'noDataSent'){
weekNumber = req.params.weekNumber;
query.weekNumber = weekNumber;
}
...
Ticket.find(query)...
I've got two collections, User and Ticket. The Ticket objects contain an objectId ref to a User object. Since I can't query the Tickets by a users name due to the ref, I'm finding all users based on a provided name and then pulling out their _id to then add to the query object. In this case, if nothing else is specified I would like the result to only return the tickets that match any of the user _ids, and if there are other fields to work the same, to match everything else and find the tickets with the user ids.
I've tried using $or
and $in
, but unless I'm doing something wrong, I can't figure out how to make this work right.
Doing this returns an error, and I'm not even sure how to go about using $or
in this case.
let users = [];
User.find( { $or: [ { firstname: requestor }, { lastname: requestor } ] } ).exec((err, user) => {
if (err){ return res.status.json({err: "No user(s) found"}); }
user.forEach((e) => {
users.push(new ObjectId(e._id));
});
});
Ticket.find(query, { requestor: { $in: users } } )
How can I match all of the fields in my query object and find all tickets with the user(s) _ids with this setup?
Edit: I've tried doing this to get it to search through both, and this does search through the users correctly and brings back the tickets tied to them, it is ignoring everything in the query object.
Ticket.find({
$and:
[
{ query },
{requestor:
{ $in: users.map(doc => new ObjectId(doc._id))
}
}
]
})
CodePudding user response:
You are running Ticket.find()
outside of the callback of User.find()
. While this is valid code, both of these queries are effectively queued up to go concurrently, with the the Ticket query utilizing the array of users - which the Users query has yet to populate.
In order to use the result of the Users query, you must put the next bit of code in that callback which can only be called after the query is complete:
User.find({
$or: [
{ firstname: requestor },
{ lastname: requestor }
]
}).exec((err, users) => {
if (err) return res.status.json({ err: "No user(s) found" });
Ticket.find({
requestor: {
$in: users.map(doc => new ObjectId(doc._id))
}
}).exec((err, tickets) => {
if (err) return res.status.json({ err: "No ticket(s) found" });
// do something with 'tickets'
tickets.forEach(doc => console.log(doc));
});
});
CodePudding user response:
To solve my original question of how to search through the tickets using the query object I built up as well as use $in
to find the tickets associated with the returned users, I came up with this solution that seems to work nicely.
query.requestor = { $in: users.map(doc => new ObjectId(doc._id)) };
Set the query.
to the field I want to search through, in this case the requestor
. That way I can simply do what I've been doing thus far and do a plain Ticket.find(query)