Оператор $and
- это чисто логический оператор, в котором порядок условий фильтра не играет никакой роли .
Таким образом, следующие запросы абсолютно эквивалентны из заданного значениявида:
$and: [
{ "a": 1 },
{ "b": 2 }
]
$and: [
{ "b": 2 },
{ "a": 1 }
]
Документация гласит:
$ и выполняет логическую операцию И над массивом из двух или более выражений (например,и т. д.) и выбирает документы, которые удовлетворяют всем выражениям в массиве.Оператор $ and использует оценку короткого замыкания.Если первое выражение (например) оценивается как ложное, MongoDB не будет оценивать оставшиеся выражения.
В вашем примере запись "index1"
соответствует первому фильтру "tokens.word": "I"
и документу "index3"
соответствует второму $elemMatch
фильтру.Таким образом, документ должен быть возвращен.
ОБНОВЛЕНИЕ:
Вот идея - более отправная точка на самом деле - чтобы вы приблизились к тому, что вы хотите:
db.collection.aggregate({
$addFields: { // create a temporary field
"differenceBetweenMatchPositions": { // called "differenceBetweenMatchPositions"
$subtract: [ // which holds the difference between
{ $indexOfArray: [ "$tokens.word", "I" ] }, // the index of first element matching first condition and
{ $min: { // the lowest index of
$filter: { // a filtered array
input: { $range: [ 0, { $size: "$tokens" } ] }, // that holds the indices [ 0, 1, 2, ..., n ] where n is the number of items in the "tokens" array - 1
as: "this", // which we want to access using "$$this"
cond: {
$let: {
vars: { "elem": { $arrayElemAt: [ "$tokens", "$$this" ] } }, // get the n-th element in our "tokens" array
in: {
$and: [
{ $eq: [ "$$elem.pos", "IN" ] }, // "pos" field must be "IN"
{ $eq: [ { $substrBytes: [ "$$elem.word", 0, 1 ] }, "f" ] } // 1st character of the "word" must be "f"
]
}
}
}
}
}
}]
}
}
}, {
$match: {
"differenceBetweenMatchPositions": { $lt: 0 } // we only want documents where the first condition is matched by an item in our array before the second one gets matched, too.
}
})