Mongoose's find method with $or condition does not work properly
Asked Answered
I

4

166

Recently I start using MongoDB with Mongoose on Nodejs.

When I use Model.find method with $or condition and _id field, Mongoose does not work properly.

This does not work:

User.find({
  $or: [
    { '_id': param },
    { 'name': param },
    { 'nickname': param }
  ]
}, function(err, docs) {
   if(!err) res.send(docs);
});

By the way, if I remove the '_id' part, this DOES work!

User.find({
  $or: [
    { 'name': param },
    { 'nickname': param }
  ]
}, function(err, docs) {
   if(!err) res.send(docs);
});

And in MongoDB shell, both work properly.

Ilke answered 12/9, 2011 at 0:12 Comment(0)
I
290

I solved it through googling:

var ObjectId = require('mongoose').Types.ObjectId;
var objId = new ObjectId( (param.length < 12) ? "123456789012" : param );
// You should make string 'param' as ObjectId type. To avoid exception, 
// the 'param' must consist of more than 12 characters.

User.find( { $or:[ {'_id':objId}, {'name':param}, {'nickname':param} ]}, 
  function(err,docs){
    if(!err) res.send(docs);
});
Ilke answered 13/9, 2011 at 12:7 Comment(6)
can you describe why this solution works with words? thanksAmelia
This looks like a solution to a rather specific issue. You may have to keep searching.Pyroelectric
Could you provide your reference? Why in this case param has to consist more than 12 characters? Is this specific to your problem or the requirement of ObjectId()? What if my param doesn't have 12 characters? Thanks!Colter
you can also check ObjectId as follow: const mongoose = require('mongoose'); mongoose.Types.ObjectId.isValid(objectidtocheck)Hydromechanics
@Colter it's due to mongoose will throw an error if it's not a valid ObjectId. A cleaner way to do it mentioned above me.Dorsett
Use Joi or another validation libraryLoathe
D
92

I implore everyone to use Mongoose's query builder language and promises instead of callbacks:

User.find().or([{ name: param }, { nickname: param }])
    .then(users => { /*logic here*/ })
    .catch(error => { /*error logic here*/ })

Read more about Mongoose Queries.

Debora answered 20/1, 2018 at 6:23 Comment(3)
Love it! Thanks for the heads up!Horton
Why is chaining methods like or() onto find() better than using operators like { $or: [] } in a regular JSON filter? Is this way faster? Is one just syntactic sugar for another?Innovation
Yes, the methods are syntactic sugar. It's a matter of preference. For me they sometimes read better. Other times, they make things less readable. I would say to stick with whatever makes more sense to you, but stick to one or the other. Or if you're working at a company, it would be best to go with whatever the norm is at your company and stay consistent.Debora
A
7

You can also add a mix of $or and and to give your functions more flexibility, options and robustness, like so:

var ObjectId = require("mongoose").Types.ObjectId;
var idParam = new ObjectId(param.length < 12 ? "123456789012" : param);
const {nameParam, nicknameParam, ageParam} = req.params || req.body || req.query

User.find({
        $or: [{
                _id: objId
            },
            {
                name: nameParam
            },
            {
                nickname: nicknameParam
            }
        ],
        $and: [{
            age: ageParam
        }]
    },
    function (err, docs) {
        if (!err) res.send(docs);
    }
);

So this means that your find() will look for all users where (_id = idParam OR name = nameParam OR nickname = nicknameParam) AND (age = ageParam)

I hope this helps someone out there. Cheers!!!

Abernon answered 28/11, 2021 at 10:23 Comment(0)
S
-2
router.get("/bulk", async (req, res) => {
    const filter = req.query.filter || "";

    const users = await User.find({
        $or: [
                {
                   firstName: { "$regex": filter }
                },
                {
                   lastName: { "$regex": filter }
                }
             ]
    })

    res.json({
        user: users.map(user => ({
            username: user.username,
            firstName: user.firstName,
            lastName: user.lastName,
            _id: user._id
        }))
    })
})
Spinoff answered 30/1 at 11:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.