将数组中的字符串值连接到 MongoDB 的单个字段中

假设我有一系列格式如下的文档:

Suppose that I have a series of documents with the following format:

{
    "_id": "3_0",
    "values": ["1", "2"]
}

我想获得在单个字段中连接的数组值的投影:

and I would like to obtain a projection of the array's values concatenated in a single field:

{
    "_id": "3_0",
    "values": "1_2"
}

这可能吗?我试过 $concat 但我想我不能使用 $values 作为 $concat 的数组.

Is this possible? I have tried $concat but I guess I can't use $values as the array for $concat.

推荐答案

在现代 MongoDB 版本中,您可以.您仍然不能直接"将数组应用到 $concat,但是您可以使用 $reduce 处理数组元素并生成:

In Modern MongoDB releases you can. You still cannot "directly" apply an array to $concat, however you can use $reduce to work with the array elements and produce this:

db.collection.aggregate([
  { "$addFields": {
    "values": { 
      "$reduce": {
        "input": "$values",
        "initialValue": "",
        "in": {
          "$cond": {
            "if": { "$eq": [ { "$indexOfArray": [ "$values", "$$this" ] }, 0 ] },
            "then": { "$concat": [ "$$value", "$$this" ] },
            "else": { "$concat": [ "$$value", "_", "$$this" ] }
          }    
        }
      }        
    }
  }}
])

当然结合 $indexOfArray 当它是数组的第一个"索引时,不与 "_" 下划线连接".

Combining of course with $indexOfArray in order to not "concatenate" with the "_" underscore when it is the "first" index of the array.

我的额外愿望"也得到了$sum的回答:

Also my additional "wish" has been answered with $sum:

db.collection.aggregate([
  { "$addFields": {
    "total": { "$sum": "$items.value" }
  }}
])

<小时>

一般来说,这种类型的聚合运算符会使用一组项目.这里的区别在于它表示编码表示中提供的aguments"数组",而不是当前文档中存在的数组元素".


This kind of gets raised a bit in general with aggregation operators that take an array of items. The distinction here is that it means an "array" of "aguments" provided in the coded representation a opposed to an "array element" present in the current document.

真正实现文档中存在的数组中的项目连接的唯一方法是执行某种 JavaScript 选项,例如 mapReduce:

The only way you can really do the kind of concatenation of items within an array present in the document is to do some kind of JavaScript option, as with this example in mapReduce:

db.collection.mapReduce(
    function() {
        emit( this._id, { "values": this.values.join("_") } );
    },
    function() {},
    { "out": { "inline": 1 } }
)

当然,如果您实际上并未聚合任何内容,那么最好的方法可能是在您的客户端代码中简单地执行加入"操作,以便对查询结果进行后处理.但是,如果它需要跨文档用于某种目的,那么 mapReduce 将是您唯一可以使用它的地方.

Of course if you are not actually aggregating anything, then possibly the best approach is to simply do that "join" operation within your client code in post processing your query results. But if it needs to be used in some purpose across documents then mapReduce is going to be the only place you can use it.

我可以添加例如"我希望这样的东西可以工作:

I could add that "for example" I would love for something like this to work:

{
    "items": [
        { "product": "A", "value": 1 },
        { "product": "B", "value": 2 },
        { "product": "C", "value": 3 }
    ]
}

总的来说:

db.collection.aggregate([
    { "$project": {
        "total": { "$add": [
            { "$map": {
                "input": "$items",
                "as": "i",
                "in": "$$i.value"
            }}
        ]}
    }}
])

但它不起作用,因为 $add 需要参数而不是文档中的数组.叹!:(.对此的设计"推理的一部分可以这样说,仅仅因为"它是一个数组或列表"的奇异值从转换的结果中传入,它不是保证"那些是实际上是运算符期望的有效"奇异数值类型值.至少在当前实现的类型检查"方法中不是.

But it does not work that way because $add expects arguments as opposed to an array from the document. Sigh! :(. Part of the "by design" reasoning for this could be argued that "just because" it is an array or "list" of singular values being passed in from the result of the transformation it is not "guaranteed" that those are actually "valid" singular numeric type values that the operator expects. At least not at the current implemented methods of "type checking".

这意味着现在我们仍然必须这样做:

That means for now we still have to do this:

db.collection.aggregate([
   { "$unwind": "$items" },
   { "$group": {
       "_id": "$_id",
        "total": { "$sum": "$items.value" }
   }}
])

遗憾的是,也没有办法应用这样的分组运算符来连接字符串.

And also sadly there would be no way to apply such a grouping operator to concatenate strings either.

因此,您可以希望对此进行某种更改,或者希望进行一些更改,以允许在 $map 以某种方式操作.更好的是,新的 $join 操作也会受到欢迎.但这些在撰写本文时不存在,并且可能在未来一段时间内不会存在.

So you can hope for some sort of change on this, or hope for some change that allows an externally scoped variable to be altered within the scope of a $map operation in some way. Better yet a new $join operation would be welcome as well. But these do not exist as of writing, and probably will not for some time to come.

相关文章