Mongodb多嵌套数组搜索

时间:2015-10-15 08:11:45

标签: php mongodb mongodb-query aggregation-framework

我的目标是搜索数据记录userid 1

以下是我的数据

{ "_id" : 2,
  "name" : "test", 
  "data" :[{"_id" : "1","file" : "nic", "userid" : [1,2 ]},
           {"_id" : "2","file" : "nic1","userid" : [1 ]  },
           {"_id" : 3,"file" : "nick2","userid" : [1,2 ]} 
     ]},

{ "_id" : 3,
  "name" : "test",
  "data" : [{"_id" : "1","file" : "nic","userid" : [1,2 ]  },
            {"_id" : "2","file" : "nic1", "userid" : [3,2 ] } 
      ]}

out put应该是

{ "_id" : 2,
  "name" : "test", 
  "data" :[{"_id" : "1","file" : "nic", "userid" : [1,2 ]},
           {"_id" : "2","file" : "nic1","userid" : [1 ]  },
           {"_id" : 3,"file" : "nick2","userid" : [1,2 ]} 
     ]},

{ "_id" : 3,
  "name" : "test",
  "data" : [{"_id" : "1","file" : "nic","userid" : [1,2 ]  },          
      ]}

我试过

$res=$collection->find(array("data.userid" =>array('$in'=>array('52')))); 

返回null

1 个答案:

答案 0 :(得分:1)

您需要使用.aggregate()方法才能过滤"除了单一匹配之外的任何数组内容,以及基本匹配都要简单得多,因为MongoDB不关心数据是否在数组中,只要指定的路径是正确的:

db.collection.aggregate([
    { "$match": { "data.userid": 1 } },
    { "$project": {
        "data": {
            "$setDifference": [
                { "$map": {
                    "input": "$data",
                    "as": "el",
                    "in": { 
                        "$cond": [
                            { "$setIsSubset": [ [1], "$$el.userid" ] },
                            "$$el",
                            false
                        ]
                    }
                }},
                [false]
            ]
        }
    }},
    { "$match": { "data.0": { "$exists": true } }}
])

使用PHP,这表示如下:

$collection->aggregate(array(
    array( '$match' => array( "data.userid" => 1 )),
    array(
        '$project' => array(
            'data' => array(
                '$setDifference' => array(
                    array(
                        '$map' => array(
                            'input' => '$data',
                            'as' => 'el',
                            'in' => array(
                                '$cond' => array(
                                    array( '$setIsSubset' => array(array(1),'$$el.userid') ),
                                    '$$el',
                                    FALSE
                                )
                            )
                        )
                    ),
                    array(FALSE)
                )
            )
        )
    ),
    array( '$match' => array( 'data.0' => array( '$exists' => TRUE ) ) )
))

$map运算符允许检查外部数组的每个元素,并将每个元素传递给$cond三元运算。这会对"内部"处理$setIsSubset操作。数组,以查看它是否实际上包含备用集中的一个值(在本例中为[1]),并且在进行true评估时,将返回该元素或以其他方式false

$setDifference的要点是从已修改的数组中删除这些false值,并仅返回匹配的元素。最后,$exists测试看到外部数组实际上至少有一个元素,并且由于过滤而不是空的。

返回的文档是具有匹配条件的文档,只有与指定条件匹配的数组元素。

当然,这里的运营商要求你至少拥有MongoDB 2.6作为服务器(现在这是一个相当旧的版本,至少是一个建议的更新),但如果你的版本较少,那么你需要一个传统的方法{ {3}}和$unwind

$collection->aggregate(array(
    array( '$match' => array( "data.userid" => 1 )),
    array( '$unwind' => '$data' ),
    array( '$match' => array( 'data.userid' => 1 )),
    array( 
        '$group' => array(
            '_id' => '$_id',
            'data' => array( '$push' => '$data' )
        )
    )
))