如何编写自定义函数将文档拆分为具有相同 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 的多个文档的主要内容,如果未能解决你的问题,请参考以下文章

如何将具有自定义 ID 的文档添加到 Firestore

如何在firestore 9中将具有自定义ID的文档添加到firestore

如何在 Swift 上将具有自定义 ID 的文档添加到 Firebase (Firestore)

如何将 indexPath 数组拆分为单独的 indexPath 数组,每个数组的 indexPath 具有相同的 indexPath.section

具有相同 ID 键字段的多对多

如何从 percentile_approx 代码编写自定义函数,该函数在 excel 中给出与 percentile.inc 相同的结果?