2016-08-20 83 views
5

我有一个文档集合,其中“tags”字段从空格分隔的标签列表切换到单个标签数组。我想将以前的空格分隔字段更新为所有数组,如新的传入数据。将Mongo中的字段从String转换为Array

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

如何将第一个示例中的每个文档转换为第二个示例的格式?

{ 
    "_id" : ObjectId("12345"), 
    "tags" : "red blue green white" 
} 
{ 
    "_id" : ObjectId("54321"), 
    "tags" : [ 
     "red", 
     "orange", 
     "black" 
    ] 
} 
+0

优秀的问题..我试过,但无法解决它在mongodb ..然后我抬头看着mongodb杰拉和它的工作进展.. https://jira.mongodb.org/browse/SERVER-6773 – user641887

+0

@ user641887 jira已经关闭。但是可以在没有$ split的情况下在MongoDB中执行此操作。唯一的问题是性能。 – styvane

回答

2

我们不能用$type运营商在这里过滤我们的文件,因为我们的数组中的元素的类型是“字符串”和文档中提到:

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

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

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

那么,从MongoDB版本< = 3.2,我们唯一的选择是mapReduce(),但首先让我们看看即将发布的MongoDB的另一种选择。

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

请注意,要仅分割字符串中的那些“标签”,我们需要逻辑处理来分割仅字符串的值。这里的条件是$eq,当该字段的$type等于"string"时,其评估为true。顺便说一下$type这里是3.4中的新功能。

最后,我们可以使用$out流水线阶段操作符覆盖旧集合。 但是我们需要在$project阶段中明确指定包含其他字段。

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

随着mapReduce,我们需要使用Array.prototype.split()发出子阵列中我们地图功能。我们还需要使用“查询”选项来过滤我们的文档。从那里,我们将需要迭代为“标签”使用使用bulkWrite()方法新批量操作在3.2“结果”阵列和$set新值或现在弃用Bulk()如果我们在2.6或3.0,如图here.

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'] 
相关问题