如何编写自定义函数将文档拆分为具有相同 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:
您收到错误的唯一原因是_id
s 之一不是字符串。
将$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 的多个文档的主要内容,如果未能解决你的问题,请参考以下文章
如何在firestore 9中将具有自定义ID的文档添加到firestore
如何在 Swift 上将具有自定义 ID 的文档添加到 Firebase (Firestore)
如何将 indexPath 数组拆分为单独的 indexPath 数组,每个数组的 indexPath 具有相同的 indexPath.section
如何从 percentile_approx 代码编写自定义函数,该函数在 excel 中给出与 percentile.inc 相同的结果?