我有一个包含这样数据的文档:
{
"data":"string"
"arrayofdata" :[
{},
{},
{}
]
}
我想要做的是只选择单个文档中的数据数组
我试图获得这种格式:
{ arrayofdata: [{},
{},
{}]}
我尝试的东西给了我这种不好的结果:
[ { arrayofdata: {} },
{ arrayofdata: {} },
{ arrayofdata: {} } ]
以下是我现在正在使用的内容:
async findSubElement(collection: string, subElementName: string, filter: {
id?: number,
offset?: number,
limit?: number,
order?: number,
sort?: string,
fields?: string[],
}): Promise<any[]> {
try {
const aggregatePipeline: any = [];
aggregatePipeline.push(
{
$unwind: '$' + subElementName,
},
);
if (filter.sort) {
filter.sort = subElementName + '.' + filter.sort;
}
// then we can apply filter on these documents
aggregatePipeline.push(
{
$match: {
_id: new ObjectID(filter.id),
},
},
{
$sort: {
[filter.sort ? filter.sort : subElementName + '.created_at']: filter.order || 1,
},
},
// Then, use the offset
{
$skip: filter.offset || 0,
},
// And the limit
{
$limit: filter.limit || 20,
},
);
const fields: any = {};
// If the user specified fields, build the 'fields' object in a Mongo way
if (filter.fields && filter.fields.length > 0) {
filter.fields.forEach(field => {
fields[field] = '$' + subElementName + '.' + field;
});
} else {
// If the user didn't specify any field, use a default value
fields[subElementName] = 1;
}
fields['_id'] = false;
// finally we "project" only the fields of our wanted subDocuments.
aggregatePipeline.push({
$project: fields,
});
const agg = await this.aggregate(
collection,
aggregatePipeline,
);
const result = await agg.toArray();
return result.filter(a => a);
} catch (error) {
throw error;
}
}
答案 0 :(得分:1)
您需要摆脱$unwind
阶段,只需使用$project,就像这样:
aggregatePipeline.push(
{
{
$project:
{
"_id": 0 /* get rid of _id explicitly */,
"arrayofdata": "$arrayofdata" /* only include arrayofdata field */
}
}
}
);
关于您的评论:是的,您也可以使用标准findOne()
来执行此操作。实际上,您在代码中执行的所有操作都可以在不使用聚合框架的情况下完成。请注意,sort()
,skip()
和limit()
仅在您的查询可以返回多个文档时才可用,因此对于findOne()
,它们都不起作用。但是,它们都可以使用findMany()
:
你的$ match变成了沼泽标准过滤器(findOne的第一个参数),如下所示:
collection.findOne({_id: new ObjectID(filter.id)})
您的$project
将是findOne方法的投影参数:
// exclude "_id", include "arrayofdata"
collection.findOne({...}, {"_id": 0, "arrayofdata": 1})
$sort
阶段变为.sort()
命令:
// I'm not sure about the square brackets here but if your code works then this should work, too.
collection.findOne(...).sort([filter.sort ? filter.sort : subElementName + '.created_at']: filter.order || 1)
但要注意排序部分,并确保您理解这一点:How to project in MongoDB after sort?
$skip
:
collection.findOne(...).sort(...).skip(filter.offset || 0)
还有$limit
:
collection.findOne(...).sort(...).skip(...).limit(filter.limit || 20)
总而言之,这是一个有效的查询,在您的数据上下文中可能有意义,也可能没有意义,但它在语法上是正确的:
collection.find({_id: ObjectId("597fa64617a1cdcf9ace4712")}, {"_id": 0, "arrayofdata": 1}).sort({"arraydata":1}).skip(10).limit(20)