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

Eyl*_*len 5 javascript mapreduce mongodb mongodb-query aggregation-framework

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

{
    "_id": "3_0",
    "values": ["1", "2"]
}
Run Code Online (Sandbox Code Playgroud)

我想获得在单个字段中连接的数组中的值的投影.我想以下列格式获取每个文档.

{
    "_id": "3_0",
    "values": "1_2"
}
Run Code Online (Sandbox Code Playgroud)

这可能吗?我试过$concat但我猜我不能$values用作数组$concat.

Nei*_*unn 8

在Modern MongoDB版本中,您可以.您仍然无法"直接"应用数组$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" ] }
          }    
        }
      }        
    }
  }}
])
Run Code Online (Sandbox Code Playgroud)

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

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

db.collection.aggregate([
  { "$addFields": {
    "total": { "$sum": "$items.value" }
  }}
])
Run Code Online (Sandbox Code Playgroud)

对于采用一系列项目的聚合运算符,这种类型的通常会有所提升.这里的区别在于它意味着在编码表示中提供的"aguments"的"阵列"与当前文档中存在的"数组元素"相对.

你可以真正在文档中存在的数组中实现项目串联的唯一方法是执行某种JavaScript选项,就像mapReduce中的这个示例一样:

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

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


我可以补充说"例如"我喜欢这样的事情:

{
    "items": [
        { "product": "A", "value": 1 },
        { "product": "B", "value": 2 },
        { "product": "C", "value": 3 }
    ]
}
Run Code Online (Sandbox Code Playgroud)

总的来说:

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

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

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

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

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

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


小智 5

您可以将reduce运算符与substr运算符一起使用。

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