简体   繁体   English

根据价值折叠子文档的投影

[英]Projection to collapse Sub-Document based on value

I have a data structure with a subdoc containing an array of department IDs, which are objects containing both IDs and department names. 我有一个带有子文档的数据结构,该子文档包含部门ID的数组,部门ID是包含ID和部门名称的对象。 People may be in a large number of departments and have a separate ID for each, so that their record might look like this: 人们可能在很多部门中,并且每个部门都有一个单独的ID,因此他们的记录可能如下所示:

{ 
    "_id" : "xxxxx", 
    "dept_ids" : [
        {
            "dept_id" : "dd7867535", 
            "dept_name" : "d1"
        }, 
        {
            "dept_id" : "dl97087079", 
            "dept_name" : "d2"
        }
    ]
}

I'm putting together an aggregate query with a known subset of departments and I'd like to use the value of "dept_name" to roll up the values, so that the resulting document looks like this: 我正在将汇总查询与部门的已知子集放在一起,并且我想使用“ dept_name”的值来汇总这些值,以便生成的文档如下所示:

{ 
    "_id" : "xxxxx", 
    "d1" : "dd7867535",
    "d2" : "dl97087079"
}

I'm having trouble finding a way to do this within the aggregation framework. 我很难在聚合框架中找到实现此目的的方法。 Any suggestions would be welcome. 欢迎大家提出意见。

Thanks, Alex 谢谢,亚历克斯

If you actually have a MongoDB suporting $replaceRoot and $arrayToObject then you can use this: 如果您实际上有一个支持$replaceRoot$arrayToObject的MongoDB,则可以使用以下命令:

db.collection.aggregate([
  { "$replaceRoot": {
    "newRoot": {
      "$mergeObjects": [
        { "_id": "$_id" },
        { "$arrayToObject": {
          "$map": {
            "input": "$dept_ids",
            "in": { "k": "$$this.dept_name", "v": "$$this.dept_id" }
          }
        }}
      ]
    }
  }}
])

But you don't even need that, and simply transform the returned documents instead: 但是您甚至不需要它,只需转换返回的文档即可:

db.collection.find().map(d =>
  Object.assign(
    { _id: d._id },
    d.dept_ids.reduce((acc,dep) => Object.assign(acc,{ [dep.dept_name]: dep.dept_id }), {})
  )
);

In modern ECMASCRIPT environments, not the Mongo shell but something like NodeJS you can clean up the syntax a bit. 在现代ECMASCRIPT环境中,不是Mongo Shell,而是像NodeJS这样的环境,您可以稍微清理一下语法。 ie with the NodeJS driver: 即使用NodeJS驱动程序:

const mapper = ({ _id, dept_ids }) => ({
  _id, ...dept_ids.reduce((acc, { dept_name: k, dept_id: v }) => ({ ...acc, [k]: v }),{})
});

let results = await db.collection('departments').find().map(mapper).toArray();

Both produce the same result: 两者产生相同的结果:

{ "_id" : "xxxxx", "d1" : "dd7867535", "d2" : "dl97087079" }

So you really don't need to process things through the aggregation pipeline that can be done quite simply from the received data on the client. 因此,您实际上不需要通过聚合管道来处理事务,而这可以非常简单地从客户端上收到的数据中完成。 You're not "reducing" any data, which is actually the point of the aggregation framework. 您没有“减少”任何数据,这实际上是聚合框架的重点。 So tranformations like this really "should" be done in post processing the cursor results instead. 因此,实际上应该在对游标结果进行后处理中完成这样的转换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM