Dựa trên yêu cầu của bạn, một trong những cách tiếp cận có thể là thiết kế lược đồ của bạn, theo cách mà mỗi tài liệu có khả năng để chứa nhiều tài liệu và bản thân nó hoạt động như một vùng chứa có giới hạn .
{
"_id":Number,
"doc":Array
}
Mỗi tài liệu trong bộ sưu tập sẽ hoạt động như một vùng chứa có giới hạn và các tài liệu sẽ được lưu trữ dưới dạng mảng trong doc
đồng ruộng. doc
trường là một mảng, sẽ duy trì thứ tự chèn. Bạn có thể giới hạn số lượng tài liệu ở n
. Vì vậy, _id
trường của mỗi tài liệu vùng chứa sẽ tăng dần theo n
, cho biết số lượng tài liệu mà một tài liệu vùng chứa có thể chứa.
Bằng cách làm những điều này, bạn tránh thêm extra fields
vào tài liệu, extra indices
, unnecessary sorts
.
Chèn bản ghi đầu tiên
tức là khi bộ sưu tập trống.
var record = {"name" : "first"};
db.col.insert({"_id":0,"doc":[record]});
Chèn các bản ghi tiếp theo
- Xác định
_id
của tài liệu vùng chứa cuối cùng vànumber
trong số các tài liệu mà nó lưu giữ. - Nếu số lượng tài liệu mà nó lưu giữ ít hơn
n
, sau đó cập nhật tài liệu thecontainer với tài liệu mới, khác tạo một containerdocument mới.
Giả sử rằng mỗi container document
có thể giữ 5
tối đa là tài liệu và chúng tôi muốn chèn một tài liệu mới.
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 ]
});
}
})
Lưu ý rằng tập hợp aggregation
, chạy ở phía máy chủ và rất hiệu quả, cũng lưu ý rằng tập hợp aggregation
sẽ trả lại cho bạn một tài liệu thay vì con trỏ trong các phiên bản previous to 2.6
. Vì vậy, bạn sẽ cần sửa đổi đoạn mã trên để chỉ chọn từ một tài liệu duy nhất thay vì lặp lại con trỏ.
Chèn một tài liệu mới vào giữa các tài liệu
Bây giờ, nếu bạn muốn chèn một tài liệu mới vào giữa các tài liệu 1
và 2
, chúng tôi biết rằng tài liệu sẽ nằm trong vùng chứa có _id=0
và phải được đặt ở second
vị trí trong doc
mảng của vùng chứa đó.
vì vậy, chúng tôi sử dụng $each
và $position
toán tử để chèn vào các vị trí cụ thể.
var record = {"name" : "insertInMiddle"};
db.col.update(
{
"_id" : 0
}, {
$push : {
"doc" : {
$each : [record],
$position : 1
}
}
}
);
Xử lý quá dòng
Bây giờ, chúng ta cần xử lý các tài liệu overflowing
trong mỗi container
, giả sử chúng tôi chèn một tài liệu mới vào giữa, trong vùng chứa có _id=0
. Nếu vùng chứa đã có 5
tài liệu, chúng ta cần move the last document to the next container
và làm như vậy cho đến khi tất cả các thùng chứa tài liệu trong khả năng của chúng, cuối cùng nếu được yêu cầu, chúng tôi cần tạo một thùng chứa để chứa các tài liệu tràn.
Thao tác phức tạp này nên được thực hiện ở phía máy chủ . Để xử lý điều này, chúng ta có thể tạo một tập lệnh như tập lệnh dưới đây và register
nó với 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);
}
}
Vì vậy, after every insertion in between
, chúng ta có thể gọi function
này bằng cách chuyển id vùng chứa, handleOverFlow(containerId)
.
Tìm nạp tất cả các bản ghi theo thứ tự
Chỉ cần sử dụng $unwind
toán tử trong aggregate pipeline
.
db.col.aggregate([{$unwind:"$doc"},{$project:{"_id":0,"doc":1}}]);
Tài liệu Đặt hàng lại
Bạn có thể lưu trữ từng tài liệu trong một vùng chứa có giới hạn với trường "_id":
.."doc":[{"_id":0,","name":"xyz",...}..]..
Nắm giữ mảng "doc" của vùng chứa có giới hạn mà bạn muốn sắp xếp lại các mục.
var docArray = db.col.find({"_id":0})[0];
Cập nhật id của họ để sau khi sắp xếp, thứ tự của mặt hàng sẽ thay đổi.
Sắp xếp mảng dựa trên _id của chúng.
docArray.sort( function(a, b) {
return a._id - b._id;
});
cập nhật lại vùng chứa có giới hạn, với mảng tài liệu mới.
Nhưng sau đó, tất cả mọi thứ đều tóm gọn lại cách tiếp cận nào là khả thi và phù hợp với yêu cầu của bạn nhất.
Trả lời câu hỏi của bạn:
Tài liệu dưới dạng Mảng.
sử dụng $each
và $position
toán tử trong db.collection.update()
hoạt động như được mô tả trong câu trả lời của tôi.
Đúng. Nó sẽ ảnh hưởng đến hiệu suất, trừ khi bộ sưu tập có rất ít dữ liệu.
Đúng. Với Bộ sưu tập có giới hạn, bạn có thể mất dữ liệu.