项目仅匹配从不同文档分组的数组项

时间:2016-06-13 08:35:02

标签: mongodb aggregation-framework

假设我们有两种不同类型的文件。第一类商店addresses和第二类商店cars and boats for each person identified by its national document (dni)

考虑以下4个文件:

/* 1 */
{
    "_id" : {
        "i" : ObjectId("575e6522d51ef71dbe128bd0"),
        "dni" : "72999995X"
    },
    "data" : {
        "addresses" : [ 
            {
                "type" : "avenue",
                "name" : "gran via",
                "number" : 112
            }, 
            {
                "type" : "street",
                "name" : "mayor",
                "number" : 23
            }
        ]
    }
}

/* 2 */
{
    "_id" : {
        "i" : ObjectId("575e657dd51ef71dbe128bd1"),
        "dni" : "72999994B"
    },
    "data" : {
        "addresses" : [ 
            {
                "type" : "avenue",
                "name" : "gran via",
                "number" : 112
            }, 
            {
                "type" : "road",
                "name" : "N-112",
                "km" : 430
            }, 
            {
                "type" : "road",
                "name" : "N-112",
                "km" : 440
            }
        ]
    }
}

/* 3 */
{
    "_id" : {
        "i" : ObjectId("575e65cdd51ef71dbe128bd2"),
        "dni" : "72999995X"
    },
    "data" : {
        "cars" : [ 
            {
                "fuel" : "gas",
                "color" : "black",
                "brand" : "BMW"
            }, 
            {
                "fuel" : "gas",
                "color" : "white",
                "brand" : "Mercedes"
            }
        ],
        "boats" : [ 
            {
                "year" : 1998,
                "engines" : 1,
                "tank" : 2250
            }, 
            {
                "year" : 2015,
                "engines" : 2,
                "tank" : 4100
            }
        ]
    }
}

/* 4 */
{
    "_id" : {
        "i" : ObjectId("575e664ad51ef71dbe128bd3"),
        "dni" : "72999994B"
    },
    "data" : {
        "cars" : [ 
            {
                "fuel" : "diesel",
                "color" : "gray",
                "brand" : "BMW"
            }, 
            {
                "fuel" : "gas",
                "color" : "blue",
                "brand" : "Opel"
            }, 
            {
                "fuel" : "gas",
                "color" : "black",
                "brand" : "BMW"
            }
        ],
        "boats" : [ 
            {
                "year" : 2001,
                "engines" : 2,
                "tank" : 2550
            }, 
            {
                "year" : 2014,
                "engines" : 3,
                "tank" : 4000
            }
        ]
    }
}

问题是......我怎样才能从每个数组中获得符合适用于2个以上不同文档的条件的项目?

例如......谁住在mayor并且拥有gas辆汽车和项目匹配值。

这是我的方法:

db.getCollection('test').aggregate([
    {'$group': {'_id': {'dni': '$_id.dni'}, 'data': {'$addToSet':'$data'}}},
    {'$match': {'$and': [{'data.cars.fuel':'gas'}, {'data.addresses.name':'mayor'}]}},
    {'$unwind': '$data'},
    {'$unwind': {'path': '$data.cars', 'preserveNullAndEmptyArrays': true}},
    {'$unwind': {'path': '$data.addresses', 'preserveNullAndEmptyArrays': true}},
    {'$match': {'$or': [{'data.cars.fuel':'gas'}, {'data.addresses.name':'mayor'}]}},
    {'$project': {'data.cars': 1, 'data.addresses': 1}}
])

这个管道实际上返回了我想要的东西:

/* 1 */
{
    "_id" : {
        "dni" : "72999995X"
    },
    "data" : {
        "cars" : {
            "fuel" : "gas",
            "color" : "black",
            "brand" : "BMW"
        }
    }
}

/* 2 */
{
    "_id" : {
        "dni" : "72999995X"
    },
    "data" : {
        "cars" : {
            "fuel" : "gas",
            "color" : "white",
            "brand" : "Mercedes"
        }
    }
}

/* 3 */
{
    "_id" : {
        "dni" : "72999995X"
    },
    "data" : {
        "addresses" : {
            "type" : "street",
            "name" : "mayor",
            "number" : 23
        }
    }
}

但是我必须更改$and by $or in $match stage,因为在$unwind阶段之后,每个值都转到了不同的文档。

如果是GENERIC解决方案,那就没关系,但事实并非如此。如果现在我想获得同时拥有'gas' carsboats with 2+ engines的人

,该怎么办?

$match阶段看起来像这样:

{'$match': {'$and': [{'data.cars.fuel':'gas'}, {'data.boats.engines':{'$gt':1}}]}},

但两次都应该是$and,因为在$unwind之后,汽车和船只都属于同一份文件。

(例如:)

/* 6 */
{
    "_id" : {
        "dni" : "72999994B"
    },
    "data" : {
        "cars" : {
            "fuel" : "gas",
            "color" : "black",
            "brand" : "BMW"
        },
        "boats" : {
            "year" : 2014,
            "engines" : 3,
            "tank" : 4000
        }
    }
}

是否有可能$unwind他们使用不同的文件?

否则......如何在不改变架构的情况下到达通用管道来实现各种查询?

0 个答案:

没有答案