将Mongo中的某些字段从String转换为Array

ElP*_*nte 5 mapreduce mongodb mongodb-query aggregation-framework

我有一组文档,其中"标签"字段从空格分隔的标签列表切换到单个标签的数组.我想将以前的空格分隔字段更新为所有数组,如新的传入数据.

我也遇到了$ type选择器的问题,因为它将类型操作应用于单个数组元素,即字符串.所以按类型过滤只会返回所有内容.

如何将每个看起来像第一个示例的文档转换为第二个示例的格式?

{
    "_id" : ObjectId("12345"),
    "tags" : "red blue green white"
}
{
    "_id" : ObjectId("54321"),
    "tags" : [
        "red",
        "orange",
        "black"
    ]
}
Run Code Online (Sandbox Code Playgroud)

sty*_*ane 4

我们不能使用$type运算符来过滤此处的文档,因为数组中元素的类型是“字符串”,如文档中所述:

当应用于数组时,$type 匹配指定 BSON 类型的任何内部元素。例如,当匹配 $type : 'array' 时,如果字段具有嵌套数组,则文档将匹配。当字段本身是数组时,它不会返回结果。

但幸运的是,MongoDB 还提供了$exists可以在此处与数字数组索引一起使用的运算符。

现在我们如何更新这些文档?

好吧,从 MongoDB 版本 <= 3.2 开始,我们唯一的选择是mapReduce()首先看看即将发布的 MongoDB 版本中的其他选择。

从 MongoDB 3.4 开始,我们可以使用$project文档并使用$split运算符将​​字符串拆分为子字符串数组。

请注意,为了仅拆分那些字符串“标签”,我们需要一个逻辑$cond处理来仅拆分字符串值。这里的条件是当字段的 等于时$eq评估为。顺便说一句,这是 3.4 中的新增内容。true$type"string"$type

最后,我们可以使用管道阶段运算符覆盖旧集合$out但我们需要明确指定阶段中包含其他字段$project

db.collection.aggregate(
     [
        { "$project": { 
            "tags": { 
                "$cond": [ 
                    { "$eq": [ 
                        { "$type": "$tags" }, 
                        "string"
                    ]}, 
                    { "$split": [ "$tags", " " ] }, 
                    "$tags" 
                ] 
            } 
        }},
        { "$out": "collection" }
    ]
)
Run Code Online (Sandbox Code Playgroud)

对于mapReduce,我们需要使用 来在我们的映射函数Array.prototype.split()中发出子字符串数组。我们还需要使用“查询”选项来过滤文档。从那里,我们需要 使用3.2 中的 new 方法或现在已弃用的方法(如果我们在 2.6 或 3.0 上)使用批量操作来迭代“结果”数组和“标签”的新值,如此处所示$setbulkWrite()Bulk()

db.collection.mapReduce(
    function() { emit(this._id, this.tags.split(" ")); }, 
    function(key, value) {}, 
    { 
        "out": { "inline": 1 }, 
        "query": { 
            "tags.0": { "$exists": false }, 
            "tags": { "$type": 2 }
        }
    }
)['results']
Run Code Online (Sandbox Code Playgroud)