Я просто потратил значительную часть своего времени на то, чтобы попытаться реализовать решение Асии выше с объектными сравнениями, а не строгое равенство. Поэтому я решил поделиться этим здесь.
Допустим, вы расширили свой вопрос от userIds до полных пользователей. Вы хотите найти все документы, в которых каждый элемент в массиве users
присутствует в другом массиве пользователей: [{user: 1, group: 3}, {user: 2, group: 5},...]
Это не сработает: db.collection.find({"users":{"$not":{"$elemMatch":{"$nin":[{user: 1, group: 3},{user: 2, group: 5},...]}}}}})
, потому что $ nin работает только для строгого равенства. Поэтому нам нужно найти другой способ выражения «Не в массиве» для массивов объектов. И использование $where
слишком сильно замедлит запрос.
Решение:
db.collection.find({
"users": {
"$not": {
"$elemMatch": {
// if all of the OR-blocks are true, element is not in array
"$and": [{
// each OR-block == true if element != that user
"$or": [
"user": { "ne": 1 },
"group": { "ne": 3 }
]
}, {
"$or": [
"user": { "ne": 2 },
"group": { "ne": 5 }
]
}, {
// more users...
}]
}
}
}
})
Чтобы завершить логику: $ elemMatch соответствует всем документам, у которых есть пользователь, который не находится в массив. Таким образом, $ не будет соответствовать всем документам, в которых есть все пользователи в массиве.