node.js - 将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 查询转换为聚合查询,或者有没有其他方法来实现这个......??
我正在尝试修改上述动态查询以适用于用户传递的任何查询,但处理所有查询变得困难。
有没有更好的方法来处理这种情况,例如更改用户传递的查询或在服务器端处理它的方式,或者我应该如何更改我的代码以支持用户传递的所有类型的查询..??
任何帮助将不胜感激
解决方案
如果这真的是您的输入
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)
推荐阅读
- sql - Sqllite sum() 在加入第二个表时返回错误值
- java - 简单的基于动态 JTree 的 S3 存储桶/对象选择器示例
- python-3.x - 使用 xml.etree.ElementTree 在 Python3 中的特定位置查找 XML 标记并插入新标记
- java - 如何将具有相同返回类型的不同泛型类型的列表数据放入?
- azure - Azure 自动缩减将踢出可能连接到因自动缩减而自动终止的实例的第二个用户
- python - flash_ask 不喜欢整个 python
- python - 使用键作为数字处理特殊 JSON
- swift - 我可以根据子类对象的属性创建谓词吗?
- azure-cognitive-search - 定义 Azure 搜索分数的阈值
- html - 在表格内显示表格标题标签