聚合后如何取回原始文档
我有一个情况下,我想要查询一个文件的集合有一个数组字段“窗体”下的项目数量。 要解决的问题只是要返回具有“封闭”特定状态的“表单”中包含的所有文档的文档。
所以这里是集合中两个不同文档的示例:
{ "_id" : "Tvq444454j", "name" : "Jim", "forms" : [ { "name" : "Jorney", "status" : "closed" }, { "name" : "Women", "status" : "void" }, { "name" : "Child", "status" : "closed" }, { "name" : "Farm", "status" : "closed" } ] }, { "_id" : "Tvq579754r", "name" : "Tom", "forms" : [ { "name" : "PreOp", "status" : "closed" }, { "name" : "Alert", "status" : "closed" }, { "name" : "City", "status" : "closed" }, { "name" : "Country", "status" : "closed" } ] }
而预期的结果是:
{ "_id" : "Tvq579754r", "name" : "Tom", "forms" : [ { "name" : "PreOp", "status" : "closed" }, { "name" : "Alert", "status" : "closed" }, { "name" : "City", "status" : "closed" }, { "name" : "Country", "status" : "closed" } ] }
由于在这种情况下没有标准的查询操作符来匹配数组的所有元素,所以通过使用聚合来find解决scheme。 这将返回集合中具有所有“表单”元素设置为“closures”状态的文档的_id。
db.forms.aggregate([ {$unwind: "$forms" }, {$group: { _id: "$_id", status: {$addToSet: "$forms.status" }}}, {$unwind: "$status"}, {$sort: { _id: 1, status: -1 }}, {$group: {_id: "$_id", status: {$first: "$status"}}}, {$match:{ status: "closed" }} ])
因此,我期望在结果中返回许多文档,所以我想避免发布另一个查找或一系列查找来获取与返回的_id匹配的文档。
考虑到这一点,是否有任何方法可以将原始文档从聚合中恢复成与集合中的forms完全相同的forms,而仍然执行这种types的过滤?
属于愚蠢的聚合技巧类别是一种常常被忽视的技术。
查询完成所有分组,围绕文档_id,这是该文档的唯一标识符。 所以要考虑的要点是整个文档实际上是一个唯一的标识符。 所以,而不是只存储在_id键,使用整个文档。
{$project: { _id: { _id: "$_id", name: "$name", forms: "$forms" }, forms: "$forms"} },
在这里完成的任何东西都是由_id保存的原始文件。 在所有其他汇总阶段结束时,发出最终的$项目以恢复真正的原始文档格式:
{$project: { _id: "$_id._id", name: "$_id.name", forms: "$_id.forms"}}
然后你将有你想要的过滤结果。 这种技术在使用高级过滤(例如在此查询的情况下)时可以非常方便,因为它消除了对所有结果发出额外查找的需求。
此外,在这种情况下,您只需要查找一组将匹配某些条件的结果,则可以使用$ match运算符作为聚合stream水线的第一阶段。 这不仅有助于减less工作集大小,而且还是您可以使用索引的唯一阶段,并且可以显着提高查询性能。
整个过程一起:
db.forms.aggregate([ {$match: { "forms.status": "closed" } }, {$project: { _id: { _id: "$_id", name: "$name", forms: "$forms" }, forms: "$forms"} }, {$unwind: "$forms"}, {$group: { _id: "$_id", status: {$addToSet: "$forms.status"}}}, {$unwind: "$status"}, {$sort: { _id: 1, status: -1} }, {$group: { _id: "$_id", status: {$first: "$status"} }}, {$match: { status: "closed"}}, {$project: { _id: "$_id._id", name: "$_id.name", forms: "$_id.forms"}} ])