【问题标题】:MongoDB How filtered by key array (not value)?MongoDB 如何通过键数组(不是值)过滤?
【发布时间】:2016-02-26 12:45:41
【问题描述】:

我有一个带有用户键的数组。

ID 为:array('111', '333');的用户

我会得到以下方案,只有具有这些 id 的用户的一些字段(名称)。

    {
        "_id" : "78787878",
        "users" : {
            "111" : {
                "name" : "William",
                "e" : "w@sas..."
                ...
            },
            "222" : {
                "name" : "Sarah",
                "e" : "s@sas..."
            },
            "333" : {
                "name" : "Marie",
                "e" : "m@sas..."
            },..
         },..
}

我的预期结果是这样的:

{
            "_id" : "78787878",
            "users" : {
                "111" : {
                    "name" : "William",
                },
                "333" : {
                    "name" : "Marie",
                }
             }
    }

我试过了:

db.getCollection('instagram').find({'_id' : '78787878', 'users' : { '$in' : ['456726', '2945551665'] } }, { '_id' : 0, 'users.name' : 1 })

如何进行此类查询?我可以使用“findOne”还是应该使用“聚合”?

已编辑(问题仍在继续):

如果我按如下方式修改架构,则根据 cmets:

{
    "_id" : "78787878",
    "users" : [
        {
            "id": 111,
            "name" : "William",
            "e" : "w@sas..."
            ...
        },
        {
            "id": 222,
            "name" : "Sarah",
            "e" : "s@sas..."
        },
        {
            "id": 333,
            "name" : "Marie",
            "e" : "m@sas..."
        },..
     ]
}

如果我使用 $in 它会返回所有... 为什么不应用过滤器?

$filter = array(111, 333);
$this->db->{$collection}->find(array('_id' => '78787878', 'users.id' => array('$in' => $filter)), array('users' => 1));

users.id 是 Int32。

【问题讨论】:

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


    【解决方案1】:

    您可能希望像这样重组数据

    {
        "_id" : "78787878",
        "users" : [
            {
                "id": "111",
                "name" : "William",
                "e" : "w@sas..."
                ...
            },
            {
                "id": "222",
                "name" : "Sarah",
                "e" : "s@sas..."
            },
            {
                "id": "333",
                "name" : "Marie",
                "e" : "m@sas..."
            },..
         ]
    }
    

    那么你就可以像这样轻松查询了

    db.instagram.find({'users.id':{$in: ['111', '333']}})
    

    【讨论】:

    • 我已经应用了新的架构,但查询仍然对我不起作用。
    • 你用 mongo shell 试过了吗?还是其他 mongoDB 客户端?
    • 我也在“Robomongo”中尝试了查询,结果仍然没有过滤。查询: db.getCollection('mycollection').find({ '_id' : '78787878', 'users.id' : {'$in' : [111, 333]}, }, { 'users' : 1 })
    【解决方案2】:

    对于这样的架构,如果您有哈希键,那么查询将非常困难,除非您可以更改它以便将用户 ID 嵌入到数组中。

    但是,对于这种结构,唯一可用的选择是通过投影来获得所需的输出。您需要一种机制来构造投影,如下面的查询中所示

    db.instagram.find(
        { "_id": "78787878"}, 
        { "users.111": 1, "users.333": 1 }
    );
    

    这将产生想要的输出

    {
        "_id" : "78787878",
        "users" : {
            "111" : {
                "name" : "William",
                "e" : "w@sas..."
            },
            "333" : {
                "name" : "Marie",
                "e" : "m@sas..."
            }
        }
    }
    

    因此,给定输入数组,其中包含您只想投影的用户 ID,您可以通过 JavaScript 的 Array.reduce() 函数构造投影文档,该函数将数组简化为对象。 考虑以下方法来创建上述查询:

    var userIds = ['111', '333'],
        query = { "_id": "78787878"},
        projection = userIds.reduce(function(o, v, i) {
            o["users."+v] = 1;
            return o;
        }, {});
    db.instagram.find(query, projection)
    

    【讨论】:

    • 我已经应用了新的架构,但查询仍然对我不起作用。
    • @ephramd 你改变了什么架构?上述查询仅适用于您在问题中拥有的原始架构。
    • 我编辑了这个问题(最后我点了编辑)。我试图应用最简单的结构,没有散列键。
    • @ephramd 您使用的是哪个 MongoDB 版本?
    • 我使用 mongodb 1.6.12 和 PHP 5.6.17
    猜你喜欢
    • 2018-09-02
    • 2016-09-11
    • 2021-12-22
    • 2013-02-21
    • 2019-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    相关资源
    最近更新 更多