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

Concatenate string values in array in a single field in MongoDB

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

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

并且我想获得串联在单个字段中的数组值的投影:

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

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

的数组

在现代 MongoDB 版本中可以。您仍然无法 "directly" 将数组应用于 $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" ] }
          }    
        }
      }        
    }
  }}
])

为了"concatenate"与"_"下划线结合$indexOfArray当然是"first"数组的索引。

我的附加 "wish" 也得到了 $sum 的回答:

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

这种情况通常会在采用项目数组的聚合运算符中出现。这里的区别在于它意味着编码表示中提供的 "array" of "aguments" 与当前文档中存在的 "array element" 相反。

唯一可以真正将文档中数组中的项目串联起来的方法是使用某种 JavaScript 选项,如 mapReduce 中的示例:

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

当然,如果您实际上没有聚合任何东西,那么最好的方法可能是在 post 处理查询结果时在客户端代码中简单地执行 "join" 操作。但是如果它需要跨文档用于某些目的,那么 mapReduce 将是唯一可以使用它的地方。


我可以补充一点 "for example" 我希望这样的东西能起作用:

{
    "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 需要参数而不是文档中的数组。叹! :(。"by design" 的部分推理可能会争辩说 "just because" 它是一个数组或 "list" 从转换结果传入的奇异值它不是 "guaranteed" 这些实际上是运算符期望的 "valid" 单数值类型值。至少在 "type checking".

当前实现的方法中不是

这意味着现在我们仍然需要这样做:

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

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

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

您可以使用 reduce operator together with the substr 运算符。

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

Mongo 4.4 开始,$function 聚合运算符允许应用自定义 javascript 函数来实现 MongoDB 查询语言不支持的行为。

例如,为了连接一个字符串数组:

// { "_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 有 3 个参数:

  • body,就是要申请的函数,其参数是要加入的数组。
  • args,其中包含 body 函数作为参数的记录中的字段。在我们的例子中 "$values".
  • lang,这是编写body函数的语言。目前只有 js 个可用。