首页 > 解决方案 > 将mongo查询转换为聚合查询?

问题描述

我是 MongoDB 的新手。我有一个用例,应该将mongo 查询转换为聚合查询

我有以下两个集合:

items: {_id: "something", "name": "raj", "branch": "IT", subItems: ["subItemId","subItemId"]}

subItems: {_id: "something", "city": "hyd", list: ["adsf","adsf"]}

用户传递的查询是:

{
    "query": { "name": "raj", "subItems.loc": "hyd" },
    "sort": { "name": 1 },
    "projection": { "_id": 0, "branch": 1, "subItems.loc": 1 }
}

我可以通过以下方式创建动态查询:

        let itemConditions: any[] = [];
        let subItemConditions: any[] = [];
        let itemProjection: {[k:string]: any} = {};
        let subItemProjection: {[k:string]: any} = {};
        subItemConditions.push({$in: ["$_id", "$$subItems"]}); // Default condition to search files in the subItems collection
        let isAnysubItemProj = false;
        Object.keys(reqQuery).forEach(prop => {
            let value = reqQuery[prop];
            if(prop.includes('subItems.')) {
                key = prop.split(".")[1];
                if(key === '_id') value = new ObjectId(value);
                subItemConditions.push({$eq: [`$${prop}`, value]});
                return;
            }                
            itemConditions.push({$eq: [`$${prop}`, value]});
        });
        if(config.projection)
            Object.keys(config.projection).forEach(prop => {
                if(prop.includes('subItems.')) {
                    isAnysubItemProj = true;
                    const key = prop.split(".")[1];
                    subItemProjection[key] = config.projection[prop];
                    return;
                }
                itemProjection[prop] = config.projection[prop];
            });
        if(isAnysubItemProj) itemProjection['subItems'] = 1;
        let subItemPipeline: any[] = [];
        subItemPipeline.push(
            { $match: {
                $expr: {
                    $and: subItemConditions
                }
            }
        });
        if(Object.keys(subItemProjection).length)
            subItemPipeline.push({$project: subItemProjection});
        let query: any[] = [
            { 
                $match: {
                    $expr : {
                        $and: itemConditions
                    }
                }
            },
            {
                $addFields: {
                    subItems: {
                        $map: {
                            input: "$subItems",
                            as: "id",
                            in: { $toObjectId: "$$id" }
                        }
                    }
                }
            },
            {
                $lookup: {
                    from: "subItems",
                    let: {subItems: "$subItems"},
                    pipeline: subItemPipeline,
                    as: "subItems"
                }
            }
        ];
        if(config.sort && Object.keys(config.sort).length) query.push({$sort: config.sort});
        if(Object.keys(itemProjection).length) query.push({$project: itemProjection});
        const items = await collection.aggregate(query).toArray();

上面的代码仅适用于分别比较项目和子项目的相等性,但用户可以发送不同类型的查询,例如:

{
  "query": { $or: [{"name": "raj"}, {subItems: {$gt: { $size: 3}}}], "subItems.city": "hyd" },     
  "sort": { "name": 1 },     
  "projection": { "_id": 0, "branch": 1, "subItems.loc": 1 } 
}

{
  "query": { $or: [{"name": "raj"}, {"subItems.city": {"$in" : ["hyd", "ncr"]}}], "subItems.list": {"$size": 2} },     
  "sort": { "name": 1 },     
  "projection": { "_id": 0, "branch": 1, "subItems.loc": 1 } 
}

有没有简单的方法可以将这个普通的 MongoDB 查询转换为聚合查询,或者有没有其他方法来实现这个......??

我正在尝试修改上述动态查询以适用于用户传递的任何查询,但处理所有查询变得困难。

有没有更好的方法来处理这种情况,例如更改用户传递的查询或在服务器端处理它的方式,或者我应该如何更改我的代码以支持用户传递的所有类型的查询..??

任何帮助将不胜感激

标签: node.jsmongodbmongodb-queryaggregation-frameworkaggregation

解决方案


如果这真的是您的输入

input = {
    "query": { "name": "raj", "subItems.loc": "hyd" },
    "sort": { "name": 1 },
    "projection": { "_id": 0, "branch": 1, "subItems.loc": 1 }
}

那么聚合管道将很简单:

let pipeline = [
   {$match: input.query},
   {$sort: input.sort},
   {$project: input.projection}
]

db.collection.aggregate(pipeline)

推荐阅读