检查MongoDB数组中的所有元素是否与给定查询匹配

时间:2013-10-24 19:27:31

标签: mongodb mongodb-shell

以下是我的文档的外观:

nookstore = {
     "name": "Nook store",
     "categories": ["bookstore"],
     "working_hours": [
        {"opens": 8*60*60, "closes": 21*60*60 },
        {"opens": 8*60*60, "closes": 21*60*60 },
        {"opens": 8*60*60, "closes": 21*60*60 },
        {"opens": 8*60*60, "closes": 21*60*60 },
        {"opens": 8*60*60, "closes": 21*60*60 },
        {"opens": 8*60*60, "closes": 21*60*60 },
        {"opens": 9*60*60, "closes": 20*60*60 },
     ]
  }

  ...

kindlestore = {
     "name": "Kindle store",
     "categories": ["bookstore"],
     "working_hours": [
        {"opens": 0, "closes": 24*60*60 },
        {"opens": 0, "closes": 24*60*60 },
        {"opens": 0, "closes": 24*60*60 },
        {"opens": 0, "closes": 24*60*60 },
        {"opens": 0, "closes": 24*60*60 },
        {"opens": 0, "closes": 24*60*60 },
        {"opens": 0, "closes": 24*60*60 },
     ],
  }

我正在寻找24小时营业的商店,即working_hours的{​​strong> 0的每个元素在[{1}}开启并在24*60*60关闭的商店(午夜后的几秒钟。

我尝试使用$all$elemMatch,但是如果数组中至少有一个元素符合给定条件(我不需要),它们可以用于我需要匹配的情况

2 个答案:

答案 0 :(得分:1)

虽然我认为如果您修改架构以将特殊状态包含为另一个字段(open24hours),这将是最好的,您可以使用聚合框架来查找匹配项。

db.stores.aggregate({$unwind : '$working_hours' }, 
   { $group : { 
       _id : { 
         name: '$name', 
         opens: '$working_hours.opens', 
         closes: '$working_hours.closes' }, 
      total: { $sum : 1 }
      }
  }, 
  { $match : { total : 7 } })

这会打开打开的小时数,然后打开名称上的组,打开和关闭时间,从而形成一个独特的组合,然后总计每个组合的匹配数。如果总数为7,则在所有7天内匹配。您可以进行更多匹配,仅在opens0 closes找到86400

结果:

{
    "result" : [
            {
                    "_id" : {
                            "name" : "Kindle store",
                            "opens" : 0,
                            "closes" : 86400
                    },
                    "total" : 7
            }
    ],
    "ok" : 1
}

答案 1 :(得分:1)

您可以使用聚合框架来完成,可能有多种方式。这是一个组合,可以在午夜到午夜的单个开放/关闭时间结束时找到独特的开/关时间和匹配。

db.stores.aggregate(
  [ 
    { $unwind: '$working_hours' },
    { $group: { _id: '$name', times: { $addToSet: '$working_hours' } } },
    { $unwind: '$times' },
    { $group: { _id: '$_id', times: { $push: '$times' }, cnt: { $sum: 1 } } },
    { $match: { 'times.opens': 0, 'times.closes': 86400, cnt: 1 } }
  ]
)

编辑:另一个可能更好的选择是尽早匹配,不必对不相关的值进行分组;

db.stores.aggregate(
  [
    { $unwind: '$working_hours' },
    { $match: { 'working_hours.opens': 0, 'working_hours.closes': 86400 } },
    { $group: { _id: '$name', cnt: { $sum: 1 } } },
    { $match: { 'cnt': 7 } }
  ]
)

EDIT2:通过查找没有非匹配时间的所有商店,也可以在没有聚合框架的情况下完成;

db.stores.find({
  'working_hours': { 
    $not: { 
      $elemMatch: {
        $or:[ { 'opens': { $ne: 0 } }, { 'closes': { $ne: 86400 } } ]
      }
    }
  }
}).pretty()