使用$ indexOfArray查找第一个匹配元素$ gte的索引

时间:2019-03-30 21:11:11

标签: mongodb aggregation-framework array-indexing

MongoDB具有$indexOfArray可让您查找元素的数组索引,例如:

$indexOfArray: ["$article.date", ISODate("2019-03-29")]

是否可以将比较运算符与$indexOfArray一起使用,例如:

$indexOfArray: ["$article.date", {$gte: ISODate("2019-03-29")}]

1 个答案:

答案 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和然后您就需要提取。