MongoDB - 仅检索匹配的子文档和根文档

时间:2013-10-04 10:20:52

标签: mongodb

编辑: 问题解决了,见下文。

我有以下文件:

db.clients.insert({
    _id: ObjectId("524d720d8d3ea014a52e95bb"),
    company: "Example",
    logins: [
        {
            "name": "John Smith",
            "username": "test",
            "password": "eF9wnBEys0OzL5vmR/OHGCaekHiw/Miy+XvbDdayxeo=",
            "email": "a@a.com",
            "last": null,
            "roles": ["CONFIG"]
        },
        {
            "name": "Guest",
            "username": "guest",
            "password": "K/gYODb7XPo0erySvL276DyPi4+stPPK4jM3pJ8aaVg=",
            "email": "a@a.com",
            "last": null,
            "roles": []
        }
    ]
});

现在,我想使用此文档验证我的客户端。但是,我不想检索每个子登录,我只想要匹配的那个。

这就是我使用聚合的原因:

db.clients.aggregate(
    {
        "$project": {
            "login": "$logins",
            "_id": 0
        }
    },
    {
        "$unwind": "$login"
    },
    {
        "$group": {
            "_id": "$login.username",
            "login": {
                "$first": "$login"
            }
        }
    },
    {
        "$match": {
            "login.username": "test",
            "login.password": "eF9wnBEys0OzL5vmR/OHGCaekHiw/Miy+XvbDdayxeo=",
        }
    }
);

哪个好,给我:

{
        "result" : [
                {
                        "_id" : "test",
                        "login" : {
                                "name" : "John Smith",
                                "username" : "test",
                                "password" : "eF9wnBEys0OzL5vmR/OHGCaekHiw/Miy+XvbDdayxeo=",
                                "email" : "a@a.com",
                                "last" : null,
                                "roles" : [
                                        "CONFIG"
                                ]
                        }
                }
        ],
        "ok" : 1
}

但现在,棘手的部分是我想检索根文档字段。例如_idcompany

但无论我尝试什么,我都无法做到。你有解决方案吗? :)


编辑:

好吧,实际上并不是那么难。对不起!

db.clients.aggregate(
    {
        "$project": {
            "login": "$logins",
            "_id": "$_id",
            "company": "$company"
        }
    },
    {
        "$unwind": "$login"
    },
    {
        "$group": {
            "_id": "$login.username",
            "login": {
                "$first": "$login"
            },
            "clientId": {
                "$first": "$_id"
            },
            "company": {
                "$first": "$company"
            },
        }
    },
    {
        "$match": {
            "login.username": "test",
            "login.password": "eF9wnBEys0OzL5vmR/OHGCaekHiw/Miy+XvbDdayxeo=",
        }
    }
);

2 个答案:

答案 0 :(得分:10)

您可以使用find$位置投影运算符执行此操作:

 
db.clients.find({
        "logins.username": "test",
        "logins.password": "eF9wnBEys0OzL5vmR/OHGCaekHiw/Miy+XvbDdayxeo=",
    }, {
        "logins.$": 1,
        "company": 1
    })

投影中的$包含查询中匹配的logins数组元素的索引。

输出:

 
{
  "_id": ObjectId("524d720d8d3ea014a52e95bb"),
  "company": "Example",
  "logins": [
    {
      "name": "John Smith",
      "username": "test",
      "password": "eF9wnBEys0OzL5vmR/OHGCaekHiw/Miy+XvbDdayxeo=",
      "email": "a@a.com",
      "last": null,
      "roles": [
        "CONFIG"
      ]
    }
  ]
}

答案 1 :(得分:1)

稍短的变体:

db.clients.aggregate(
  {$match:{"logins.username":"test"}},
  {$unwind:"$logins"},
  {$match:{"logins.username":"test","logins.password":"eF9wnBEys0OzL5vmR/OHGCaekHiw/Miy+XvbDdayxeo="}}
)

输出是:

{
        "result" : [
                {
                        "_id" : ObjectId("524d720d8d3ea014a52e95bb"),
                        "company" : "Example",
                        "logins" : {
                                "name" : "John Smith",
                                "username" : "test",
                                "password" : "eF9wnBEys0OzL5vmR/OHGCaekHiw/Miy+XvbDdayxeo=",
                                "email" : "a@a.com",
                                "last" : null,
                                "roles" : [
                                        "CONFIG"
                                ]
                        }
                }
        ],
        "ok" : 1
}