Вот еще одно решение, использующее один документ для текущей версии и всех старых версий:
{
_id: ObjectId("..."),
data: [
{ vid: 1, content: "foo" },
{ vid: 2, content: "bar" }
]
}
data
содержит все версии.Массив data
имеет порядок , упорядочен , новые версии получат $push
ed только до конца массива.data.vid
- это идентификатор версии, который является инкрементным числом.
Получить самую последнюю версию:
find(
{ "_id":ObjectId("...") },
{ "data":{ $slice:-1 } }
)
Получить конкретную версию с помощью vid
:
find(
{ "_id":ObjectId("...") },
{ "data":{ $elemMatch:{ "vid":1 } } }
)
Возврат только указанных полей:
find(
{ "_id":ObjectId("...") },
{ "data":{ $elemMatch:{ "vid":1 } }, "data.content":1 }
)
Вставить новую версию: (и предотвратить одновременную вставку/ update)
update(
{
"_id":ObjectId("..."),
$and:[
{ "data.vid":{ $not:{ $gt:2 } } },
{ "data.vid":2 }
]
},
{ $push:{ "data":{ "vid":3, "content":"baz" } } }
)
2
- это vid
текущей последней версии, а 3
- добавляемая новая версия.Поскольку вам нужна самая последняя версия vid
, легко получить следующую версию vid
: nextVID = oldVID + 1
.
Условие $and
гарантирует, что 2
является самой последней vid
.
Таким образом, нет необходимости в уникальном индексе, но логика приложения должна позаботиться об увеличении vid
при вставке.
Удалить конкретную версию:
update(
{ "_id":ObjectId("...") },
{ $pull:{ "data":{ "vid":2 } } }
)
Вот и все!
(запомните 16 МБ на документ)