Mongodb $存在于 mongodb 中的 $expr 中

Mongodb $exists inside $expr in mongodb

我想在加入时添加多个条件。加入满足以下条件的文档(属于同一集合):

  1. 有异性
  2. 在主要文档年龄偏好和主要文档之间有年龄(IF EXISTS)在外国文档偏好(即双向检查)之间有age(IF EXISTS)

我的尝试如下,但有两个问题:

  1. $exists 不能在 $expr 内部使用 idk why
  2. 年龄查询是目前的一种方式
$lookup: {
       "from": "appusers",
       "let": { 'gen': "$gender",'pref': "$preference" },
       "pipeline": [{
         $match: {$expr: {
         $and: [
             { $ne: ["$gender", "$$gen"]},
             { $or: [
              {$exists: {"$age": false}},
              {$and: [
                 { $gte: ["$age", '$$pref.age_from' ] },
                 { $lte: [ "$age", '$$pref.age_to' ] }
               ]}
             ]}
           ]
        }}}],
   
       "as": "matches"
   }

示例: 输入文档:

    {
      name: "person1",
      age: 36,
      gender: "Male",
      preference: {
        age_from: 25,
        age_to: 35
      }
    }
    
    {
      name: "person2",
      age: 18,
      gender: "Female",
      preference: {
        age_from: 25,
        age_to: 40
      }
    }
    
    {
      name: "person3",
      age: 26,
      gender: "Female",
      preference: {
        age_from: 30,
        age_to: 35
      }
    }
    
    {
      name: "person4",
      age: 26,
      gender: "Female",
      preference: {
        age_from: 30,
        age_to: 40
      }
    }

输出: 对于第 1 个人,匹配数组将仅显示第 4 个人(同样第 4 个人匹配将显示第 1 个人)即:

  {
    name: person1,
    age: 36,
    gender: "Male",
    preference: {
      age_from: 28,
      age_to: 35
    },
    matches: [
      {
        name: person4,
        ...
      }
  
    ]
  }

我看过 this and 但没有帮助

$exists can't be used inside $expr idk why

$expr Allows the use of aggregation expressions within the query language, and $exists不是聚合运算符,

您只需要更正两件事:

  • 先把$expr条件放在$and条件里面
  • $expr放在最后一个$and条件中
db.appusers.aggregate([
  {
    $lookup: {
      from: "appusers",
      let: { gen: "$gender", pref: "$preference" },
      pipeline: [
        {
          $match: {
            $and: [
              { $expr: { $ne: ["$gender", "$$gen"] } },
              {
                $or: [
                  { age: { $exists: false } },
                  {
                    $expr: {
                      $and: [
                        { $gte: ["$age", "$$pref.age_from"] },
                        { $lte: ["$age", "$$pref.age_to"] }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        }
      ],
      as: "matches"
    }
  }
])

Playground

对于$exists问题,你可以用$ifNull包裹age,然后用$eq来检查是否存在。

对于 2 向年龄匹配,我认为您只需要为 person4 到 person1 重复从 person1 到 person4 的年龄匹配条件。尽管在您当前给定的测试用例中,由于 person4 的年龄不符合 person1 的偏好,因此找不到匹配项。

db.appusers.aggregate([
  {
    "$match": {
      name: "person1"
    }
  },
  {
    $lookup: {
      "from": "appusers",
      "let": {
        "a": "$age",
        "gen": "$gender",
        "pref": "$preference"
      },
      "pipeline": [
        {
          $match: {
            $expr: {
              $and: [
                {
                  $ne: [
                    "$$gen",
                    "$gender"
                  ]
                },
                {
                  $and: [
                    {
                      $or: [
                        {
                          $eq: [
                            {
                              "$ifNull": [
                                "$age",
                                "age-not-exists"
                              ]
                            },
                            "age-not-exists"
                          ]
                        },
                        {
                          $and: [
                            {
                              $gte: [
                                "$age",
                                "$$pref.age_from"
                              ]
                            },
                            {
                              $lte: [
                                "$age",
                                "$$pref.age_to"
                              ]
                            }
                          ]
                        }
                      ]
                    },
                    {
                      $or: [
                        {
                          $eq: [
                            {
                              "$ifNull": [
                                "$$a",
                                "age-not-exists"
                              ]
                            },
                            "age-not-exists"
                          ]
                        },
                        {
                          $and: [
                            {
                              $gte: [
                                "$$a",
                                "$preference.age_from"
                              ]
                            },
                            {
                              $lte: [
                                "$$a",
                                "$preference.age_to"
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          }
        }
      ],
      "as": "matches"
    }
  }
])

这里是Mongo playground供您参考。

您可以使用 $eq undefined 作为字段 age 而不是 $exists

{
   "from": "appusers",
   "let": { 'gen': "$gender",'pref': "$preference" },
   "pipeline": [{
     $match: {$expr: {
     $and: [
         { $ne: ["$gender", "$$gen"]},
         { $or: [
          {$eq: ["$age" , undefined]},
          {$and: [
             { $gte: ["$age", '$$pref.age_from' ] },
             { $lte: [ "$age", '$$pref.age_to' ] }
           ]}
         ]}
       ]
    }}}],

   "as": "matches"
}