# #json #database #mongodb #go #import
Вопрос:
Я создаю клиент MongoDB для приложения Go, используя драйвер MongoDB Go. В частности, у меня есть две базы данных с одной коллекцией в каждой. Эти коллекции могут быть асинхронно изменены разными клиентами, поэтому мне нужно периодически синхронизировать их, сохраняя последний отредактированный документ среди документов с одним и тем же id
полем
Две базы данных хранятся на разных хостах, поэтому мне нужно экспортировать коллекцию с одного хоста с помощью mongoexport
и импортировать на другой хост с помощью mongoimport
.
Я уже пробовал использовать mongoimport --collection=myColl --mode=merge
, но это не соответствует моей цели, потому что просто переопределяет конфликтующие документы из myColl
импортированных.
Моя идея состоит в том, чтобы импортировать json во временную коллекцию, но я не знаю, как сравнивать временные метки во время процесса агрегации/слияния.
Мои коллекции структурированы так, есть идеи?
Коллекция 1
{"_id":"K1","value":"VAL1","timest":{"$date":"2021-09-26T09:05:09.942Z"}}
{"_id":"K2","value":"VAL2","timest":{"$date":"2021-09-26T09:05:10.234Z"}}
Коллекция 2
{"_id":"K2","value":"VAL3","timest":{"$date":"2021-09-26T09:15:09.942Z"}}
{"_id":"K3","value":"VAL4","timest":{"$date":"2021-09-26T09:15:10.234Z"}}
Желаемое Поведение
Конфликт
{"_id":"K2","value":"VAL2","timest":{"$date":"2021-09-26T09:05:10.234Z"}}
{"_id":"K2","value":"VAL3","timest":{"$date":"2021-09-26T09:15:09.942Z"}}[LATEST]
Выход
{"_id":"K1","value":"VAL1","timest":{"$date":"2021-09-26T09:05:09.942Z"}}
{"_id":"K2","value":"VAL3","timest":{"$date":"2021-09-26T09:15:09.942Z"}}
{"_id":"K3","value":"VAL4","timest":{"$date":"2021-09-26T09:15:10.234Z"}}
Комментарии:
1. Монгоимпорт на самом деле не создан для этого. Я бы выбрал маршрут отправки всех данных с одного хоста на другой по HTTP-почте. Затем получатель может объединить данные с любой логикой, которую вы хотите, обновить свою базу данных и отправить объединенные данные обратно первому хосту, который затем может продолжить и обновить свои собственные данные.
Ответ №1:
Вы можете использовать $merge
Приведенное ниже объединение testdb1.coll
testdb2.coll
выполняется на основе того же _id
и сохраняет документ с последней датой. Если _id
не найдено, то документ вставляется.
Данные в
testdb1.coll
[{"_id" "K2","value" "VAL3","timest" (date "2021-09-26T09:15:09.942Z")}
{"_id" "K3","value" "VAL4","timest" (date "2021-09-26T09:15:10.234Z")}]
testdb2.coll
[{"_id" "K1","value" "VAL1","timest" (date "2021-09-26T09:05:09.942Z")}
{"_id" "K2","value" "VAL2","timest" (date "2021-09-26T09:05:10.234Z")}]
Результаты
testdb2.coll (после слияния)
{"_id": "K1", "value": "VAL1", "timest": {"$toDate": "2021-09-26T09:05:09.942Z"}}
{"_id": "K2", "value": "VAL3", "timest": {"$toDate": "2021-09-26T09:15:09.942Z"}}
{"_id": "K3", "value": "VAL4", "timest": {"$toDate": "2021-09-26T09:15:10.234Z"}}
Запрос
(вместо $let
того, чтобы вы могли бы использовать $$new
)
client.db("testdb1").collection("coll").aggregate(
[
{
"$merge": {
"into": {
"db": "testdb2",
"coll": "coll"
},
"on": [
"_id"
],
"let": {
"p_ROOT": "$ROOT"
},
"whenMatched": [
{
"$replaceRoot": {
"newRoot": {
"$cond": [
{
"$gt": [
"$p_ROOT.timest",
"$timest"
]
},
"$p_ROOT",
"$ROOT"
]
}
}
}
],
"whenNotMatched": "insert"
}
}
])
Комментарии:
1. Я понял логику, которой я должен следовать, но, используя golang, я должен использовать эту функцию. pkg.go.dev/go.mongodb.org/mongo-driver@v1.7.2/…. У меня возникли некоторые проблемы с преобразованием вашего запроса в запрос, используемый этой библиотекой.
2. вложенные
bson.D{{...}}
могут это сделать взгляните на этот поиск агрегации в примерах go, было бы очень легко преобразовать его, но он немного увеличится, также для$merge
чтения документов о том, как выводить данные в коллекции. В Java, например, мы должныaggregate().toCollection();
, если у нас есть$merge
или$out
как последний этап
Ответ №2:
Вы можете выполнить следующие действия в конвейере агрегации:
- используйте
$unionWith
для объединения 2 коллекций $sort
чтобы заказать их поtimest
- используйте
$first
для получения последнего документа - используйте
$replaceRoot
, чтобы получить окончательную форму, которую вы хотите
Вот игровая площадка Монго для вашей справки.
Комментарии:
1.Спасибо за ваш ответ. Я понял логику, которой я должен следовать, но, используя golang, я должен использовать эту функцию. pkg.go.dev/go.mongodb.org/mongo-driver@v1.7.2/.… У меня возникли некоторые проблемы с преобразованием вашего синтаксиса в синтаксис, используемый в этой библиотеке, для которого требуется bson.D для запроса.
2. решение хорошее и простое, но оно не работает, если коллекции находятся в разных базах данных, а OP имеет их в разных базах данных.