Нет, это невозможно с $indexOfArray
, так как это будет искать только совпадение равенства с выражением в качестве второго аргумента.
Вместо этого вы можете сделатьконструкция, подобная этой:
db.data.insertOne({
"_id" : ObjectId("5ca01e301a97dd8b468b3f55"),
"array" : [
ISODate("2018-03-01T00:00:00Z"),
ISODate("2018-03-02T00:00:00Z"),
ISODate("2018-03-03T00:00:00Z")
]
})
db.data.aggregate([
{ "$addFields": {
"matchedIndex": {
"$let": {
"vars": {
"matched": {
"$arrayElemAt": [
{ "$filter": {
"input": {
"$zip": {
"inputs": [ "$array", { "$range": [ 0, { "$size": "$array" } ] }]
}
},
"cond": { "$gte": [ { "$arrayElemAt": ["$$this", 0] }, new Date("2018-03-02") ] }
}},
0
]
}
},
"in": {
"$arrayElemAt": [{ "$ifNull": [ "$$matched", [0,-1] ] },1]
}
}
}
}}
])
, которая вернулась бы для $gte
из Date("2018-03-02")
:
{
"_id" : ObjectId("5ca01e301a97dd8b468b3f55"),
"array" : [
ISODate("2018-03-01T00:00:00Z"),
ISODate("2018-03-02T00:00:00Z"),
ISODate("2018-03-03T00:00:00Z")
],
"matchedIndex" : 1
}
или -1
, где условие былоне выполнено, чтобы соответствовать $indexOfArray
.
Основная предпосылка - использовать $zip
, чтобы "соединиться" с позициями индекса массива, которыегенерируется из $range
и $size
массива.Это может быть передано в состояние $filter
, которое вернет ВСЕ соответствующие элементы в предоставленное состояние.Здесь это первый элемент «пары» (являющийся исходным содержимым массива) через $arrayElemAt
, соответствующий указанному условию с использованием $gte
{ "$gte": [ { "$arrayElemAt": ["$$this", 0] }, new Date("2018-03-02") ] }
$filter
вернет либо ВСЕ элементы после (в случае $gte
), либо пустой массив, где ничего не было найдено.В соответствии с $indexOfArray
требуется только первое совпадение , которое выполняется с помощью другой обертки $arrayElemAt
на выходе для позиции 0
.
Поскольку результатом может быть пропущенное значение (что и происходит с $arrayElemAt: [[], 0]
), тогда вы используете [$ifNull][8]
для проверки результата и передачи массива из двух элементов обратно с -1
в качестве второго элементав случае, если вывод не был определен.В любом случае этот «спаренный» массив имеет второй элемент (индекс 1
), извлеченный снова через $arrayElemAt
, чтобы получить первый соответствующий индекс условия.
Конечно, поскольку вы хотите сослаться на все это выражение, в конце оно просто читает немного чище в пределах $let
, но это необязательно, так как вы можете "встроить" в $ifNull
, если требуется.
Так что возможно , это немного сложнее, чем поместить выражение диапазона внутри $indexOfArray
.
Обратите внимание, что любое выражение , которое на самом деле возвращает одиночное значение для соответствия равенству , просто отлично.Но поскольку операторы, такие как $gte
, возвращают boolean
, то это не будет равным какому-либо значению в массиве, и, следовательно, сортировка с $filter
и тогда извлечение - это то, что вам нужно.