简体   繁体   English

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

[英]Concatenate string values in array in a single field in 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"
}

Is this possible?这可能吗? I have tried $concat but I guess I can't use $values as the array for $concat .我试过$concat但我想我不能使用$values作为$concat的数组。

In Modern MongoDB releases you can.在现代 MongoDB 版本中,您可以。 You still cannot "directly" apply an array to $concat , however you can use $reduce to work with the array elements and produce this:您仍然不能“直接”将数组应用于$concat ,但是您可以使用$reduce来处理数组元素并生成以下内容:

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" ] }
          }    
        }
      }        
    }
  }}
])

Combining of course with $indexOfArray in order to not "concatenate" with the "_" underscore when it is the "first" index of the array.当然与$indexOfArray结合,以便在它是数组的“第一个”索引时"_"下划线“连接”。

Also my additional "wish" has been answered with $sum :我的额外“愿望”也得到了$sum回答:

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

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.这里的区别在于它意味着编码表示中提供的“参数”的“数组”,与当前文档中存在的“数组元素”相反。

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 :您真正可以在文档中存在的数组中进行项目串联的唯一方法是执行某种 JavaScript 选项,就像mapReduce 中的这个示例一样

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

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.但是如果它需要跨文档用于某些目的,那么 mapReduce 将是唯一可以使用它的地方。


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 }
    ]
}

And in aggregate:总的来说:

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

But it does not work that way because $add expects arguments as opposed to an array from the document.但它不能那样工作,因为$add需要参数而不是文档中的数组。 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.而且遗憾的是,也无法应用这样的分组运算符来连接字符串。

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.因此,您可以希望对此进行某种更改,或者希望进行某种更改以允许在$map操作的范围内以某种方式更改外部作用域变量。 Better yet a new $join operation would be welcome as well.更好的是,新的$join操作也将受到欢迎。 But these do not exist as of writing, and probably will not for some time to come.但是这些在写作时并不存在,并且可能在未来一段时间内不会存在。

You can use the reduce operator together with the substr operator.您可以将reduce运算符与substr运算符一起使用。

db.collection.aggregate([
{
    $project: {
        values: {
            $reduce: {
              input: '$values',
              initialValue: '',
              in: {
                $concat: ['$$value', '_', '$$this']
              }
            }
        }   
    }       
},
{
    $project: {
        values: { $substr: ['$values', 1 , -1]}
    }       
}])

Starting in Mongo 4.4 , the $function aggregation operator allows applying a custom javascript function to implement behaviour not supported by the MongoDB Query Language.Mongo 4.4开始, $function聚合运算符允许应用自定义 javascript 函数来实现 MongoDB 查询语言不支持的行为。

For instance, in order to concatenate an array of strings:例如,为了连接字符串数组:

// { "_id" : "3_0", "values" : [ "1", "2" ] }
db.collection.aggregate(
  { $set:
    { "values":
      { $function: {
          body: function(values) { return values.join('_'); },
          args: ["$values"],
          lang: "js"
      }}
    }
  }
)
// { "_id" : "3_0", "values" : "1_2" }

$function takes 3 parameters: $function有 3 个参数:

  • body , which is the function to apply, whose parameter is the array to join. body ,这是要应用的函数,其参数是要加入的数组。
  • args , which contains the fields from the record that the body function takes as parameter. args ,其中包含body函数作为参数的记录字段。 In our case "$values" .在我们的例子中"$values"
  • lang , which is the language in which the body function is written. lang ,这是编写body函数的语言。 Only js is currently available.目前只有js可用。

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

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