什么是在MongoDB中存储一组文件的好方法,其中订单很重要?我需要轻松地将文档插入任意位置,并可能在以后重新排序.
我可以为每个项目分配一个越来越多的数字并按其排序,或者我可以排序_id
,但我不知道如何在其他文档之间插入另一个文档.说我要插入一个元素之间的事情sequence
的5
和元素用sequence
的6
?
我的第一个猜测是增加sequence
以下所有元素,以便使用类似的查询为新元素留出空间db.items.update({"sequence":{$gte:6}}, {$inc:{"sequence":1}})
.我对数据库管理的有限理解告诉我,像这样的查询会很慢并且通常是一个坏主意,但我很高兴能够得到纠正.
我想我可以将新元素设置sequence
为5.5
,但我认为这会很快变得混乱.(再次,如果我错了,请纠正我.)
我可以使用带有保证订单的上限集合,但如果我需要增加集合,那么我会遇到问题.(再一次,我也可能错了.)
我可以让每个文档包含对下一个文档的引用,但这需要查询列表中的每个项目.(你得到一个项目,将其推送到结果数组,然后根据next
当前项目的字段获取另一个项目.)除了明显的性能问题,我也无法将一个已排序的mongo游标传递给我{#each}
spacebars阻止表达式,并在数据库更改时让它更新.(我正在使用Meteor全栈javascript框架.)
我知道一切都有它的优点和缺点,我可能只需要使用上面列出的一个选项,但我想知道是否有更好的方法来做事.
根据您的需求,一种方法可能是设计模式,以使每个文档都能够容纳一个以上的文档,并且其本身就可以作为一个有顶盖的容器。
{
"_id":Number,
"doc":Array
}
Run Code Online (Sandbox Code Playgroud)
集合中的每个文档将充当加盖的容器,并且这些文档将作为数组存储在doc
字段中。该doc
字段为数组,将保持插入顺序。您可以将文档数量限制为n
。因此_id
,每个容器文档的字段将以递增n
,表示容器文档可以容纳的文档数。
做这些你避免添加extra fields
到文档,extra indices
,unnecessary sorts
。
即当集合为空时。
var record = {"name" : "first"};
db.col.insert({"_id":0,"doc":[record]});
Run Code Online (Sandbox Code Playgroud)
_id
和所number
保存的文档。n
,则使用新文档更新容器文档,否则创建新的容器文档。假设每个人container document
最多可以容纳5
文件,我们要插入一个新文件。
var record = {"name" : "newlyAdded"};
// using aggregation, get the _id of the last inserted container, and the
// number of record it currently holds.
db.col.aggregate( [ {
$group : {
"_id" : null,
"max" : {
$max : "$_id"
},
"lastDocSize" : {
$last : "$doc"
}
}
}, {
$project : {
"currentMaxId" : "$max",
"capSize" : {
$size : "$lastDocSize"
},
"_id" : 0
}
// once obtained, check if you need to update the last container or
// create a new container and insert the document in it.
} ]).forEach( function(check) {
if (check.capSize < 5) {
print("updating");
// UPDATE
db.col.update( {
"_id" : check.currentMaxId
}, {
$push : {
"doc" : record
}
});
} else {
print("inserting");
//insert
db.col.insert( {
"_id" : check.currentMaxId + 5,
"doc" : [ record ]
});
}
})
Run Code Online (Sandbox Code Playgroud)
请注意,在aggregation
服务器端运行,并且效率很高,还请注意,aggregation
会返回文档而不是版本中的游标previous to 2.6
。因此,您需要修改上面的代码以仅从单个文档中进行选择,而不是迭代游标。
现在,如果您想在1
和之间插入一个新文档2
,我们知道该文档应放在容器内,_id=0
并应放置在该容器数组中的second
位置doc
。
因此,我们利用$each
和$position
运算符插入特定位置。
var record = {"name" : "insertInMiddle"};
db.col.update(
{
"_id" : 0
}, {
$push : {
"doc" : {
$each : [record],
$position : 1
}
}
}
);
Run Code Online (Sandbox Code Playgroud)
现在,我们需要照顾overflowing
每个文档中的文档container
,比如说我们在中间的容器中插入一个新文档_id=0
。如果容器中已经有5
文件,那么我们需move the last document to the next container
要这样做,直到所有容器都在其容量范围内保存文件为止,如果最终需要,我们需要创建一个容器来保存溢出的文件。
这个复杂的操作应该在服务器端完成。为了解决这个问题,我们可以创建一个脚本,例如下面的脚本,并register
使用mongodb 编写脚本。
db.system.js.save( {
"_id" : "handleOverFlow",
"value" : function handleOverFlow(id) {
var currDocArr = db.col.find( {
"_id" : id
})[0].doc;
print(currDocArr);
var count = currDocArr.length;
var nextColId = id + 5;
// check if the collection size has exceeded
if (count <= 5)
return;
else {
// need to take the last doc and push it to the next capped
// container's array
print("updating collection: " + id);
var record = currDocArr.splice(currDocArr.length - 1, 1);
// update the next collection
db.col.update( {
"_id" : nextColId
}, {
$push : {
"doc" : {
$each : record,
$position : 0
}
}
});
// remove from original collection
db.col.update( {
"_id" : id
}, {
"doc" : currDocArr
});
// check overflow for the subsequent containers, recursively.
handleOverFlow(nextColId);
}
}
Run Code Online (Sandbox Code Playgroud)
因此after every insertion in between
,我们可以function
通过传递容器ID 来调用它handleOverFlow(containerId)
。
只需在中使用$unwind
运算符即可aggregate pipeline
。
db.col.aggregate([{$unwind:"$doc"},{$project:{"_id":0,"doc":1}}]);
Run Code Online (Sandbox Code Playgroud)
您可以使用“ _id”字段将每个文档存储在加盖的容器中:
.."doc":[{"_id":0,","name":"xyz",...}..]..
Run Code Online (Sandbox Code Playgroud)
获取要对其项目进行重新排序的带帽容器的“ doc”数组。
var docArray = db.col.find({"_id":0})[0];
Run Code Online (Sandbox Code Playgroud)
更新其ID,以便在排序后更改项目的顺序。
根据其_id对数组进行排序。
docArray.sort( function(a, b) {
return a._id - b._id;
});
Run Code Online (Sandbox Code Playgroud)
使用新的doc数组更新加盖的容器。
但话又说回来,一切都归结为哪种方法可行并最适合您的要求。
提出您的问题:
在顺序很重要的MongoDB中存储一组文档的好方法是什么?我需要轻松地将文档插入任意位置,并可能在以后重新排序。
文档为数组。
说我想在序列为5的元素和序列为6的元素之间插入某些内容?
如我的答案所述$each
,$position
在db.collection.update()
函数中使用and 运算符。
我对数据库管理的有限了解告诉我,这样的查询会很慢,而且通常是个坏主意,但我很高兴得到纠正。
是。除非集合中的数据很少,否则它将影响性能。
我可以使用有上限的集合,该集合有保证的顺序,但是如果我需要增加集合的数量,那么我会遇到问题。(再次,我可能也错了。)
是。使用上限集合,您可能会丢失数据。
对于任何集合的任意排序,您需要一个字段来对其进行排序。我称我的为“序列”。
schema:
{
_id: ObjectID,
sequence: Number,
...
}
db.items.ensureIndex({sequence:1});
db.items.find().sort({sequence:1})
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
6196 次 |
最近记录: |