5

Is there a way to find whether the individual element exists in the mongodb document's array.

For Example: If I have a document

{
    "_id": "A",
    "userId": "B",
    "selectedUsers": ["C", "D"]
}

and I have another array as ["E", "C"].
I want to write a query which gives the result as [false, true] when userId and the above array is supplied to it because "E" is not in the selectedUsers array and "C" is in the selectedUsers array.

I Know I can just first find the document with the given userId and then use Array.find() on it for individual element. But I want to know if there's a way to do this in mongodb query.

Also, I am using nodeJS and mongoose.

Just to be clear I need to get the same functionality as the below js code using mongodb query.

// req is the http request
// Selected is the mongoose Model for above document
// usersToCheck = ["E", "C"] (this is the second array)
const result = Selected.findOne({ userId: req.userId});
const { selectedUsers } = result;
const response = usersToCheck.map(uid => {
    if(selectedUsers.some(id => id === uid)){
        return true;
    }
    return false;
})

// response = [false, true]

Now the above code have a complexity of O(n^2) assuming the size of usersToCheck and selectedUsers is n.

I want to some how get the same response as above using mongodb query. So, that I can index the collection based on the selectedUsers array and improve the time required to get the response.

Or, any other way to improve the above code is appreciated.

Thanks in advance for your help.

2
  • To be sure: Where another array as ["E", "C"] stored? In the same document or it comes from application? And query needs to check if selectedUsers doesn't have "E", but have "C"? Commented Mar 12, 2020 at 8:34
  • @Valijon the second array comes with the http request and the query needs to return and array with true/false accordingly if the respective element is present in the document's selectedUsers. Commented Mar 12, 2020 at 9:37

3 Answers 3

3

Try this one:

const result = Selected.aggregate([
  {
    $match: {
      userId: req.userId
    }
  },
  {
    $project: {
      _id: 0,
      result: {
        $map: {
          input: ["E", "C"],
          in: {
            $in: [
              "$$this",
              "$selectedUsers"
            ]
          }
        }
      }
    }
  }
]).exec();
const response = result[0].result;

MongoPlayground

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks man this works like charm. But does it improve the time complexity. I mean should I change my js code with this query or not.
@war-turtle it has the same time complexity, but executed in the server-side (inside MongoDB). All you need to do is return result attribute from result.
2

You can just use $in

db.collection.find({selectedUsers: {$in: ["E", "C"]}})

1 Comment

This would fetch the documents in which either E or C exists in the selecteUsers array, and from what I understand he just wants to check whether E or C exists in one particular document.
2

how about something like this?

var input = ['E', 'C'];

db.collection.aggregate(
    [
        {
            $match: {
                _id: 'A'
            }
        },
        {
            $unwind: '$selectedUsers'
        },
        {
            $set: {
                has: { $in: ['$selectedUsers', input] }
            }
        },
        {
            $group: {
                _id: null,
                result: { $push: '$has' }
            }
        },
        {
            $project: {
                _id: 0
            }
        }
    ])

1 Comment

The query returns the result in the order of selectedUsers. But thanks for answering as I think this query gives me the right idea on how to solve the problem

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.