MongoDB具有$indexOfArray
可让您查找元素的数组索引,例如:
$indexOfArray: ["$article.date", ISODate("2019-03-29")]
是否可以将比较运算符与$indexOfArray
一起使用,例如:
$indexOfArray: ["$article.date", {$gte: ISODate("2019-03-29")}]
答案 0 :(得分:1)
$indexOfArray
不可能,因为它只会寻找与表达式的相等匹配作为第二个参数。
相反,您可以进行如下构造:
>>> import re
>>> url = 'https://somedomain.eu/api/one/some/2018/05/data'
>>> re.sub('/[\d]{2}/', '/11/', url)
'https://somedomain.eu/api/one/some/2018/11/data'
>>> re.sub('(?<=/)[\d]{2}(?=/)', '11', url)
'https://somedomain.eu/api/one/some/2018/11/data'
将返回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
}
,其中不满足条件的情况与$indexOfArray
保持一致。
基本前提是使用$zip
以便与从数组的$range
和$size
生成的数组索引位置“配对”。可以将其提供给$filter
条件,这将使所有匹配元素返回所提供的条件。这是通过$arrayElemAt
使用$gte
匹配指定条件的“对”(原始数组内容)的 first 元素
-1
$filter
将返回(在$gte
情况下)之后的ALL元素,或者返回未找到任何内容的空数组。与$indexOfArray
一致,您只需要第一个匹配,这是通过在输出上{ "$gte": [ { "$arrayElemAt": ["$$this", 0] }, new Date("2018-03-02") ] }
位置使用另一个包装$arrayElemAt
来实现的。
由于结果可能是一个省略的值(0
会发生这种情况),因此您可以使用[$arrayElemAt: [[], 0]
来测试结果,然后将两个元素数组与$ifNull][8]
一起传递回去作为未定义输出的情况下的第二个元素。无论哪种情况,“成对”数组都通过$arrayElemAt
再次提取第二个元素(索引-1
),以获得条件的第一个匹配索引。
当然,由于您要引用整个表达式,因此它只是在$let
内最后读了一个小写字母,但这是可选的,因为如果可以,则可以$ifNull
“内联”想要的。
所以它是可能,它比将范围表达式放在$indexOfArray
内要复杂得多。
请注意,任何实际上返回相等匹配的单个值的表达式都很好。但是由于$gte
之类的运算符会返回1
,因此与数组中的任何值都不相等,因此使用$filter
和然后您就需要提取。