2013-12-11 3 views
2

Я знаю rethinkDB's insert() имеет опцию upsert. Например, из документации:RethinkDB: условный upsert (только если определенные поля совпадают)?

rethinkdb.table('marvel').insert(
    { superhero: 'Iron Man', superpower: 'Arc Reactor' }, 
    {upsert: true, return_vals: true} 
).run(conn, callback) 

Но говорят, что может быть существующим рекорд {superhero: 'Iron Man'} с неправильным или устаревшей сверхдержавой, и я хотел либо вставить { superhero: 'Iron Man', superpower: 'Arc Reactor' } или обновить существующую {superhero: 'Iron Man'} записи?

Вкратце: как можно обновить, чтобы существующие записи обновлялись, только если определенные поля совпадают?

Edit: Похоже, это делается с .Привернуть():

Вот the important bit from the replace() docs:

Вы можете иметь новые документы, вставленной если вы точечно заменить на ключевой что ISN 't в таблице

Я не уверен, что означает «точка-замена», но я предполагаю, что это просто означает заменить.

var latestDoc = { superhero: 'Iron Man', superpower: 'Arc Reactor' } 
var mergeOrCreate = function(existingDoc) { 
    if (existingDoc) { 
    return existingDoc.merge(latestDoc) 
    } else { 
    return latestDoc 
    } 
} 
rethinkdb.table('marvel') 
    .filter({ superhero: 'Iron Man'}) 
    .replace(mergeOrCreate), 
).run(conn, callback) 

Однако в тестировании, функция «» mergeOrCreate уделяется другую функцию, а не фактический документ или курсор, в качестве аргумента.

ответ

3

Ваш первый кодовый блок является ответом на ваш первый вопрос. Однако предполагается, что superhero является основным ключом для вашей таблицы.

Вы можете установить первичный ключ таблицы при его создании:

r.tableCreate('marvel', {primaryKey: 'superhero'}).run(conn, cb) 

Ваш второй блок кода имеет две ошибки.

Во-первых, функция mergeOrCreate не работает, потому что операторы if оцениваются на стороне клиента. Вы должны использовать r.branch, чтобы создать эквивалент if заявления:

var mergeOrCreate = function(existingDoc) { 
    return r.branch(existingDoc, /* if */ 
    existingDoc.merge(latestDoc), /* then */ 
    latestDoc)     /* else */ 
} 

Во-вторых, get не поддерживает тот же синтаксис, как filter. Его аргументом должно быть значение первичного ключа. Если первичный ключ superhero, то:

r.table('marvel') 
    .get('Iron Man') 

Наконец, если superhero не является первичным ключом, вы должны написать другой вид запроса. Там может быть ноль, один или несколько документов с тем же superhero. Вот один из способов его написания:

r.table('marvel') 
    .insert(
    r.table('marvel') 
    .filter({ superhero: 'Iron Man' }) 
    .coerceTo('array') 
    .do(function(docs){ 
     return r.branch(
      docs, 
      docs.merge(latestDoc), 
      latestDoc) 
     }), 
    { upsert: true }) 
    .run(conn, cb); 

Обратите внимание, что поскольку этот запрос зависит от нескольких документов, он не является атомарным.

+0

Спасибо! Не возражаете, если я задам вам пару вопросов? Должны ли условные upserts всегда выполняться с опцией insert & upsert? – mikemaccana

+0

Также что означает «point-replace» в документах replace()? – mikemaccana

+0

Нет, как вы заметили, заменить тоже можно. Точкой замены является замена после get. – AtnNn

Смежные вопросы