RethinkDB: изменения массива в реальном времени, возвращать только недавно добавленные

Кратко: я использую каналы изменений RethinkDB для просмотра изменений в конкретном документе (а не во всей таблице). Каждая запись выглядит так:

{
  "feedback": [ ],
  "id":  "bd808f27-bf20-4286-b287-e2816f46d434" ,
  "projectID":  "7cec5dd0-bf28-4858-ac0f-8a022ba6a57e" ,
  "timestamp": Tue Aug 25 2015 19:48:18 GMT+00:00
}

У меня есть один процесс, который добавляет элементы в массив feedback, и другой процесс, которому нужно следить за изменениями в массиве feedback... и затем что-то делать (в частности, транслировать только последний элемент, добавленный к отзыву через веб-сокеты). Я подключил его так, что он будет отслеживать обновления всего документа, однако для этого требуется получить полный документ, а затем получить только последний элемент в массиве отзывов. Это кажется слишком тяжелым, когда все, что мне нужно, чтобы вернуться, это последнее добавленное.

Текущий код, используемый для обновления документа:

r.table('myTable').get(uuid)
.update({feedback:r.row('feedback').append('message 1')})
.run(conn, callback)(...}

^ Это будет выполняться несколько раз в течение минуты или около того, добавляя последнее сообщение в «обратную связь».

Отслеживание изменений:

r.table('myTable').get(uuid)
.changes()
.run(conn, function(err, cursor){
  cursor.each(function(err, row){
    var indexLast = row.old_val ? row.old_val.feedback.length : 0,
        nextItem = row.new_val.feedback[indexLast];
    // ... do something with nextItem
  })
})

Наконец, вот вопрос (на самом деле 2 части):

1: Когда я обновляю документ (добавляю в отзыв), нужно ли мне запускать update для всего документа (как в моем коде выше) или можно просто добавить к массив обратной связи и покончить с этим?

2: Является ли способ, которым я это делаю выше (получение всего документа и извлечение последнего элемента из массива обратной связи), единственным способом сделать это? Или я могу сделать что-то вроде:

r.table('myTable').get(uuid)
.changes()
.pluck('feedback').slice(8) // <- kicking my ass
.run(conn, function(err, cursor){
  cursor.each(function(err, row){
    var indexLast = row.old_val ? row.old_val.feedback.length : 0,
        nextItem = row.new_val.feedback[indexLast];
    // ... do something with nextItem
  })
})

person jiveTurkey    schedule 25.08.2015    source источник


Ответы (1)


Давайте рассмотрим ваши вопросы

1: когда я обновляю документ (добавляю отзыв), нужно ли запускать обновление всего документа (как в моем коде выше),

Нет, не знаешь. Как и вы, вы обновляете только поле feedback. Не совсем документ, не так ли?

или можно просто добавить в массив отзывов и покончить с этим?

Это возможно. И ты уже это делаешь.

То, как он пишет, выглядит так, как будто ваш клиентский драйвер должен получить содержимое массива feedback, затем добавить новый элемент и обновить весь контент обратно. Но это не тот случай. Весь запрос r.row('feedback').append('message 1') сериализуется как строка JSON и передается в RethinkDB. RethinkDB запускает его атомарно на сервере. Содержимое feedback и добавление не выполняются на клиенте и не отправляются обратно на сервер.

Если вы использовали tcpdump следующим образом:

tcpdump -nl -w - -i lo0 -c 500 port 28015|strings

Вы можете видеть, что эта строка JSON отправляется на сервер RethinkDB при выполнении запроса:

[1,[53,[[16,[[15,["myTable"]],1]],[69,[[2,[3]],{"feedback":[29,[[170,[[10,[3]],"feedback"]],"doc2"]]}]]]],{}]

Да, этот единственный запрос JSON был передан по сети, а не весь документ. Надеюсь, это имеет смысл. Дополнительную информацию об этой строке JSON можно найти на странице http://rethinkdb.com/docs/writing-drivers/ и https://github.com/neumino/rethinkdbdash/blob/master/lib/protodef.js#L84

2: Является ли способ, которым я это делаю выше (получение всего документа и извлечение последнего элемента из массива обратной связи), единственным способом сделать это? Или я могу сделать что-то вроде:

В идеале мы хотим использовать скобки для получения поля документа и прослушивания изменений в этом поле. К сожалению, это еще не работает. Поэтому мы должны использовать map для его преобразования. Опять же, это выполняется на сервере, и клиенту передается только последний документ, а не весь документ:

r.table('myTable').get(1).changes().map(function(doc) {
  return doc('new_val')('feedback').default([]).nth(-1)
})
person kureikain    schedule 25.08.2015
comment
Мне потребовалось некоторое время, чтобы одобрить ответ, но я хотел сказать спасибо, именно то, что я искал! - person jiveTurkey; 29.09.2015
comment
Я очень рад, что это помогает вам - person kureikain; 29.09.2015