聚合子查询,搜索特定_id的列表

jes*_*ess 5 mongodb mongodb-query aggregation-framework

很多讲座我敢说,如果它可以在mongo的1个查询中执行这个sql等效查询:
SELECT * from collection WHERE _id NOT IN (SELECT blacklist from collection WHERE _id = 1 ) 我尝试了很多聚合但没有设法工作.

这是我的收藏:

{
    "_id" : 1,
    "blacklist" : [8,9,10,3]
    "code_postal" : 67110,
    "loc" : {
        "type" : "Point",
        "coordinates" : [ 
            7.72, 
            48.91
        ]
    }
}

{
    "_id" : 2,
 "blacklist" : [18,1,93]
    "code_postal" : 67110,
    "loc" : {
        "type" : "Point",
        "coordinates" : [ 
            7.63, 
            48.91
        ]
    }
}

{
    "_id" : 3,
     "blacklist" : [7,3]
    "code_postal" : 67110,
    "loc" : {
        "type" : "Point",
        "coordinates" : [ 
            7.7, 
            48.96
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

此查询预期的结果和此集合应该是(_id 3排除因为在_id 1的黑名单中):

{
        "_id" : 1,
        "blacklist" : [8,9,10,3]
        "code_postal" : 67110,
        "loc" : {
            "type" : "Point",
            "coordinates" : [ 
                7.72, 
                48.91
            ]
        }
    }

    {
            "_id" : 2,
         "blacklist" : [18,1,93]
            "code_postal" : 67110,
            "loc" : {
                "type" : "Point",
                "coordinates" : [ 
                    7.63, 
                    48.91
                ]
            }
        }
Run Code Online (Sandbox Code Playgroud)

问候

Rik*_*kus 4

我认为你应该省去麻烦,只使用两个查询(首先,获取黑名单,然后查询文档),但如果确实没有其他方法:

db.so.aggregate([
{
    // First, choose what fields to return (less is better)
    // and only return a certain document {_id: 1}'s blacklist.
    $project: {
        _id:         1,
        code_postal: 1,
        loc:         1,
        bl:          {
            // Only return blacklists if the parent has 
            // a certain ID.
            $cond: {
                if:   {$eq: ["$_id", 1]}, // or a different value
                then: "$blacklist",
                else: 0
            }
        }
    }
},

{
    // Group all documents in one, so that we can embed the
    // blacklist into all documents, not just in {_id:1}.
    $group: {
        _id:       null, // Group everything.
        items:     { $push: "$$ROOT" },
        blacklist: { $max: "$bl" } // "{}" is higher than "0".
                                   // This makes sure that we only
                                   // get one blacklist, not
                                   // [ [], 0, 0, 0, ... ]
    }
},

{
    // Pull the documents apart again.
    $unwind: "$items"
},

{
    $project: {
        _id:         "$items._id",
        code_postal: "$items.code_postal",
        loc:         "$items.loc",
        whitelisted: {
            // If everything in the following array is true,
            // then the _id is not in the blacklist.
            $allElementsTrue: [{
                $map: {
                    // Iterate over $blacklist
                    input: "$blacklist",
                    as:    "currentId",
                    in:    {
                        // If the ids don't match, return true.
                        $ne: ["$$currentId", "$items._id"]
                    }
                }
            }]
        }
    }
},

{
    // Only find non-blacklisted documents.
    $match: {
        "whitelisted": true
    }
}

]);
Run Code Online (Sandbox Code Playgroud)

请注意,因为这会将所有文档归为一个,所以您必须注意不要超出Mongo 的文档大小限制

这会产生以下结果:

[ 
    {
        "_id" : 1,
        "code_postal" : 67110,
        "loc" : {
            "type" : "Point",
            "coordinates" : [ 
                7.72, 
                48.91
            ]
        },
        "whitelisted" : true
    }, 
    {
        "_id" : 2,
        "code_postal" : 67110,
        "loc" : {
            "type" : "Point",
            "coordinates" : [ 
                7.63, 
                48.91
            ]
        },
        "whitelisted" : true
    }
]
Run Code Online (Sandbox Code Playgroud)