如何编写自定义函数将文档拆分为具有相同 ID 的多个文档

Posted

技术标签:

【中文标题】如何编写自定义函数将文档拆分为具有相同 ID 的多个文档【英文标题】:How to write a custom function to split a document into multiple documents of same Id 【发布时间】:2018-03-09 14:23:45 【问题描述】:

我正在尝试拆分具有以下字符串类型字段的文档:


 "_id" : "17121",
 "firstName": "Jello",
 "lastName" : "New",
 "bio" :"He is a nice person."

我想把上面的文档拆分成三个新文档例如:


"_id": "17121-1",
"firstName": "Jello"


"_id": "17121-2",
"firstName": "New"


"_id": "17121-3",
"bio": "He is a nice person."

谁能建议如何进行?

db.coll1.find().forEach(function(obj)
   // I want to extract every single field. How to iterate on the field within this Bson object(obj) to collect every field.?
);

或任何与 MongoDB 中的聚合管道有关的建议。

【问题讨论】:

【参考方案1】:

阿努。您可以使用以下两个选项。

第一个选项非常简单,但它需要您自己硬编码 _id' 索引。

db.users.aggregate([
    
        $project: 
            pairs : [
                 firstName: '$firstName', _id :  $concat : [  $substr : [ '$_id', 0, 50 ] , '-1' ]  ,
                 lastName: '$lastName', _id :  $concat : [ '$_id', '-2' ]  ,
                 bio: '$bio', _id :  $concat : [  $substr : [ '$_id', 0, 50 ] , '-3' ]  
            ]
        
    ,
    
        $unwind : '$pairs'
    ,
    
        $replaceRoot:  newRoot: '$pairs' 
    
])

第二个选项做得更多,也更棘手。但如果您需要添加另一个字段,它可能更容易扩展。

db.users.aggregate([
    
        $project: 
            pairs : [
                 firstName: '$firstName' ,
                 lastName: '$lastName' ,
                 bio: '$bio' 
            ]
        
    ,
    
        $addFields: 
            pairsReference : '$pairs'
        
    ,
     
        $unwind: '$pairs'
    ,
    
        $addFields: 
            'pairs._id' :  $concat: [  $substr : [ '$_id', 0, 50 ] , '-',  $substr: [  $indexOfArray : [ '$pairsReference', '$pairs' ] , 0, 2 ]  ] 
        
    ,
    
        $replaceRoot:  newRoot: '$pairs' 
    
])

您可以使用$out 阶段将两个查询的结果重定向到另一个集合。

UPD:

您收到错误的唯一原因是_ids 之一不是字符串。

$concat$_id)的第一个参数替换为以下表达式:

 $substr : [ '$_id', 0, 50 ] 

【讨论】:

谢谢,在这两种方法中,它都会弹出一个“errmsg”:“$concat 只支持字符串,不支持 int”。有什么建议吗? 嗯,您使用的是哪个版本的 MongoDB?我在 MongoDB 3.4.1 上,到目前为止一切正常。 我使用的是MongoDB v3.4.6版 阿努,我更新了答案。一定是因为一个或多个ids不是字符串。 也更新了查询。【参考方案2】:

您可以使用以下聚合查询。

下面的查询会将每个文档字段转换为键值文档数组,后跟 $unwind,同时保持 index$replaceRoot 合并以产生所需的输出。

$objectToArray 生成带有键(数组字段名称)-值(数组字段)对的数组(keyvalarr)。

$match 删除 _id 键值文档。

$arrayToObject 生成命名键值,同时添加新的_id 键值对并展平数组键值。

db.coll.aggregate([
  
    "$project": 
      "keyvalarr": 
        "$objectToArray": "$$ROOT"
      
    
  ,
  
    "$unwind": 
      "path": "$keyvalarr",
      "includeArrayIndex": "index"
    
  ,
  
    "$match": 
      "keyvalarr.k": 
        "$ne": "_id"
      
    
  ,
  
    "$replaceRoot": 
      "newRoot": 
        "$arrayToObject": [
          
            "k": "_id",
            "v": 
              "$concat": [
                
                  "$substr": [
                    "$_id",
                    0,
                    -1
                  ]
                ,
                "-",
                
                  "$substr": [
                    "$index",
                    0,
                    -1
                  ]
                
              ]
            
          ,
          "$keyvalarr"
        ]
      
    
  
])

【讨论】:

谢谢我得到一个“errmsg”:“$replaceRoot 阶段无法识别的选项:$newRoot,唯一有效的选项是 'newRoot'。”。你能提供一个建议吗? 抱歉查询中的拼写错误。从 `$newRoot.xml 中删除 $。更新了答案。 谢谢@Veeram,现在我得到一个“errmsg”:“$concat 只支持字符串,不支持 int”。当我搜索 msg [***.com/questions/37470172/… 时,另一篇文章建议使用 $substring,它存在于上述查询中,但我认为 $concat 的“$_id”字段是整数有问题。因此,我将 $concat 中的整个对象与 $substr 绑定并得到一个新错误“errmsg”:“$substrBytes:起始索引必须是数字类型(是 BSON 类型字符串)”。有什么建议吗? Np。您可以将数字 $_id 包装在 $substr 中。类似"v": "$concat": [ "$substr": [ "$_id", 0, 1 ] , "-", "$substr": [ "$index", 0, 1 ] ] 一个后续问题,即使您已经使用 $concatArray 来连接对象数组,它也会给出 "errmsg" : "$concatArrays 只支持数组,不支持对象"。

以上是关于如何编写自定义函数将文档拆分为具有相同 ID 的多个文档的主要内容,如果未能解决你的问题,请参考以下文章