Search code examples
node.jsdatabasemongooseselectschema

Mongoose query with multiple $or condition and array as parameter


I'm making the followed/following rules to simulate a blog/social like app, but I want to suggest to to the users only people that are not following or followed by this user, but any combination haven't worked out yet. The Schema is:

const Follower = new mongoose.model('Follower', new mongoose.Schema({    
    sent: {
        type: mongoose.Schema.Types.ObjectId,
        ref: User,
        required: true
    },
    received: {
        type: mongoose.Schema.Types.ObjectId,
        ref: User,
        required: true
    },
    pending: {
        type: mongoose.Schema.Types.Boolean,
        required: true,
        default: true
    }
}))

So, if I already sent invitation, or if the user already sent me invitation, should be excluded from the list of suggestions to follow.

So, I select 100 id's from database, but not my id, of course:

const users = await User.find({ '_id': { $ne: id }}).select('_id').limit(100)

I put these id's on an array:

let ids = []
users.forEach(user => {
    ids.push(user._id)
})

Now, I must exclude from this array of id's all users that already sent or received invitations by the user logged in, but the query returns empty:

// id from user logged in
const id = req.id

let followers = await Follower.find({ 
    $or: [{sent: id}, {received: {$in: ids}}],
    $or: [{sent: {$in: ids}}, {received: id}]
})

I've tried other queries, but to no avail. Any hints, suggestions?


Solution

  • I have not reproduce your specific schema but have you tested with:

    Follower.find({
      $and: [
        { $or: [{ sent: id }, { received: { $in: ids } }] },
        { $or: [{ sent: { $in: ids } }, { received: id }] },
      ],
    });
    

    Cause it seems that not using $and is making the query ignore your second $or. I've tested with sample data below:

    const main = async () => {
      await connectDB();
      const Test = new mongoose.model(
        "test",
        new mongoose.Schema({
          sent: {
            type: Number,
            required: true,
          },
          received: {
            type: Number,
            required: true,
          },
        })
      );
    
      function getRandomInt(max = 10) {
        return Math.floor(Math.random() * max);
      }
    
      const sampleDatabaseSize = 100;
      for (i = 0; i < sampleDatabaseSize; i++) {
        await Test.create({
          sent: getRandomInt(),
          received: getRandomInt(),
        });
      }
    
      id = 4;
      ids = [1, 2, 3];
      result = await Test.find({
        $and: [
          { $or: [{ sent: id }, { received: { $in: ids } }] },
          { $or: [{ sent: { $in: ids } }, { received: id }] },
        ],
      });
      console.log(result);