【问题标题】:Mongodb $exists inside $expr in mongodbmongodb $exists 在 mongodb 的 $expr 中
【发布时间】:2022-01-24 05:26:33
【问题描述】:

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

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

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

  1. $exists 不能在 $expr 里面使用,为什么
  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,
        ...
      }
  
    ]
  }

我查看了 thisthis 但没有帮助

【问题讨论】:

标签: mongodb mongoose mongodb-query aggregation-framework aggregation


【解决方案1】:

$exists 不能在 $expr 里面使用 idk 为什么

$expr 允许在查询语言中使用聚合表达式,而$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

【讨论】:

    【解决方案2】:

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

    对于 2 路年龄匹配,我认为您只需要从 person1 到 person4 重复从 person4 到 person1 的年龄匹配标准。尽管在您当前给定的测试用例中,找不到匹配项,因为 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 供您参考。

    【讨论】:

    • 对不起!你是对的。我现在更新了 person1 的年龄偏好
    • @artsnr This 应该适用于您更新后的 person1 年龄偏好。
    • 如果偏好不存在,它不适应这种情况....需要对年龄和偏好进行存在检查。如果两者都存在,则进行比较,否则不进行比较并包含文档
    • @artsnr 你能用你的新测试用例更新这个问题吗?
    【解决方案3】:

    您可以对字段年龄使用 $eq undefined 而不是 $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"
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-14
      • 1970-01-01
      • 2020-08-12
      • 1970-01-01
      • 2018-12-21
      • 2018-07-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多