匹配子数组的特定元素中的两个值

时间:2017-01-09 03:35:21

标签: mongodb

我有这个记录:

  {      
    "_id" : ObjectId("5864b5d03ff9b7ad4c5eaf2f"),
    "userId" : ObjectId("967de01f640b7e4729b49fce"),
    "_children" : {
      "usersCategories" : [
        {
          "categoryId" : ObjectId("4bafbe0678081f8a40cae944"),
          "status" : "GRANTED"
        },
        {
          "categoryId" : ObjectId("0d538c05c3f98b1921426d97"),
          "status" : "APPLIED"
        }
      ]
    }
  }

记录的合理性很简单:每个用户可以附加几个类别,可以是“已授予”或“已应用”。 在这种情况下,用户申请了类别0d538c05c3f98b1921426d97,但他尚未获得批准。

现在,查询。我想要一个符合该类别且已获批准的用户列表。另外,我还想确保如果userId匹配特定值(将设置为查询器),则无论状态如何,都会返回该类别。这个想法是记录所有者不应该根据状态进行过滤。

(注意:我意识到以下查询是错误的。)

因此,如果用户000000000000000000000000进行查询:

 { '$and': 
    [ 
      { '_children.usersCategories.categoryId': ObjectId('0d538c05c3f98b1921426d97') },
      { '$or': 
        [ 
          { '_children.usersCategories.status': 'GRANTED' },
          { userId: ObjectId('000000000000000000000000') } 
        ] 
      } 
    ] 
  }

如果用户967de01f640b7e4729b49fce进行查询:

 { '$and': 
    [ 
      { '_children.usersCategories.categoryId': ObjectId('0d538c05c3f98b1921426d97') },
      { '$or': 
        [ 
          { '_children.usersCategories.status': 'GRANTED' },
          { userId: ObjectId('967de01f640b7e4729b49fce') } 
        ] 
      } 
    ] 
  }

可以简化(并且仍然打破)查询,将“所有者过滤器”取出:

  { '$and': 
    [ 
      { '_children.usersCategories.categoryId': ObjectId('0d538c05c3f98b1921426d97') },
      { '_children.usersCategories.status': 'GRANTED' }
    ]

  }

明显的问题是$and将匹配完整记录。因此,如果_children.usersCategories.categoryId_children.usersCategories.status_children.usersCategories的两个不同元素中找到匹配项并不重要:记录将匹配。

然而,这个想法是将子记录与整个相匹配。我意识到简单的解决方案是:

  { '$and': 
     [ 
       { '_children.usersCategories' : 
         {
           'categoryId': ObjectId('0d538c05c3f98b1921426d97'),
           'status': 'GRANTED' 
          }
        }
     ]

   }

问题:

  • 这个最新的形式是Mongo唯一的方式,以确保所有条件都匹配文档中的一个特定子元素吗?

  • 如果是,那么查询如下:“所有具有子记录的记录,其中ID为0d538c05c3f98b1921426d97,状态为GRANTED或标志alwaysOn为真”?

1 个答案:

答案 0 :(得分:1)

如果你可以将数据结构更新到下面,你可以使用$elemMatch投影运算符来匹配第一个整个子记录。

{
    "_id": ObjectId("5864b5d03ff9b7ad4c5eaf2f"),
    "userId": ObjectId("967de01f640b7e4729b49fce"),
    "usersCategories": [{
        "categoryId": ObjectId("4bafbe0678081f8a40cae944"),
        "status": "GRANTED"
    }, {
        "categoryId": ObjectId("0d538c05c3f98b1921426d97"),
        "status": "APPLIED"
    }]
}

所以你可以使用这样的东西:

db.collection.find({}, {
    'usersCategories': {
        $elemMatch: {
            'categoryId': ObjectId('4bafbe0678081f8a40cae944'),
            'status': 'GRANTED'
        }
    }
})

对于第二部分,您可以尝试类似

的内容
db.collection.find({
    '$and': [{
        'usersCategories.categoryId': ObjectId('4bafbe0678081f8a40cae944'),
        {
            $or: {
                'usersCategories.status': 'GRANTED',
                'usersCategories.alwaysOn': true
            }
        }
    }]
})