Mongoose 自定义 $match 函数

Mongoose custom $match function

我有看起来像这样的对象

{
  name: 'Object 1',
  fruitList: ['apple','pear','orange','grape']
},
{
  name: 'Object 2',
  fruitList: ['melon','pear','apple','kiwi']
}

我需要检索在 fruitListpear 之前具有 apple 的所有对象,在此示例中,它仅表示 Object 1。我可以执行一个自定义匹配函数来遍历该列表并检查它是否符合我的条件吗?

您需要一种机制来比较相关水果的索引,并将比较结果用作 $expr 运算符的匹配条件。利用聚合管道运算符:

  • $indexOfArray - 在数组中搜索指定值的出现和 returns 第一次出现的数组索引 (zero-based)。
  • $subtract - return 两个索引之间的差异。如果值为负,则 apple 在列表中出现在 pear 之前。
  • $lt - 在 $expr 查询中使用的比较运算符,用于比较两个值,当第一个值为 return 时为真小于第二个值。

要大致了解这些运算符在聚合管道中的作用,请查看以下内容 Mongo Playground

您实际需要的查询如下:

db.collection.find({
    $expr: {
        lt: [
            { 
                $subtract: [
                    { $indexOfArray: [ '$fruitList', 'apple' ] },
                    { $indexOfArray: [ '$fruitList', 'pear' ] }
                ] 
            },
            0
        ]
    }
})

Mongo Playground


对于基于通用正则表达式的解决方案,其中 fruitList 数组可能包含一篮子各种水果(在不同情况下),例如:

"fruitList" : [ 
    "mango", 
    "Apples", 
    "Banana", 
    "strawberry", 
    "peach", 
    "Pears"
]

以下查询可以解决这一难题:

const getMapExpression = (fruit) => {
    return {
        $map: {
            input: '$fruitList',
            as: 'fruit',
            in: {
                $cond: [
                    { $regexMatch: { input: '$$fruit', regex: fruit, options: 'i' } },
                    { $literal: fruit },
                    '$$fruit'
                ]
            }
        }
    }
}

db.collection.find({
    $expr: {
        $lt: [
            { 
                $subtract: [
                    { $indexOfArray: [ getMapExpression('apple'), 'apple' ] },
                    { $indexOfArray: [ getMapExpression('pear'), 'pear' ] }
                ] 
            },
            0
        ]
    }
})