mongodb $exists 在 mongodb 的 $expr 中

Posted

技术标签:

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

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

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

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

    $exists 不能在 $expr 里面使用,为什么 年龄查询是目前的一种方式
$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 和 this 但没有帮助

【问题讨论】:

也许看看***.com/questions/68255363/or-with-if-and-in-mongodb/… 我们可以提供一些示例数据集和预期输出吗? @ray 我已经添加了示例数据 【参考方案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"

【讨论】:

以上是关于mongodb $exists 在 mongodb 的 $expr 中的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB 聚合:$exists 的任何值

Mongodb $exists 查询不返回正确的文档

如何将sql查询转换为mongodb查询中的exists

prisma.exists 方法不适用于 mongodb Atlas

mongoDB常用命令

MongoDB Aggregation SQL Union 和 SQL Exists like 子句