如何通过任意 属性 在 rethinkdb (reql) 中插入文档?
How can I upsert a document in rethinkdb (reql) by an arbitrary property?
我有一个 .itemId
来自第三方,不是我生成的。
我需要在数据库中查找它,如果不存在则更新或插入它。
我试过使用食谱中的这个例子:https://www.rethinkdb.com/docs/cookbook/javascript/#manipulating-documents
const res = await this.r.table('products').filter({itemId: item.itemId})
.limit(1)
.replace(doc => {
return this.r.branch(
doc.eq(null),
this.r.expr(item).merge({created_at: this.r.now()}),
doc.merge(item).merge({updated_at: this.r.now()})
)
}, {
returnChanges: true
}).run(this.conn);
if (res.replaced) {
return res.changes[0].new_val;
} else {
return item; // doc was never inserted as everything in `res` is `0`.
}
res.changes
如果该文档不存在并且我在它不在数据库中后搜索它,则未定义。它从未被插入。
有没有办法简化给定任意 属性 对象的 upsert()
命令?
在 "else" 子句中,您应该执行插入查询,并且代码中的分支子句是无用的(查询永远不会 return "null" 因此项目不会 "created")
有几种方法可以解决这个问题:
最好的方法是使用 itemId(或 r.uuid(itemId))作为主键并使用冲突子句进行插入。
如果你不能
一种方法是尝试替换,如果没有替换任何内容,则插入:
this.r.table('products').filter({itemId: item.itemId})
.limit(1)
.replace(
doc => doc.merge(item).merge({updated_at: this.r.now()}),
{ returnChanges: true }
)
.do(res => res('replaced').eq(1).branch(
res,
r.table('products').insert(
{ ...item, created_at: this.r.now()},
{ returnChanges: true }
)
))
.run()
另一种方法是尝试查看是否存在并使用索引进行更新:
this.r.table('products').filter({itemId: item.itemId})
.nth(0)
.default(null)
.do(res =>
r.table('products').insert(
{
...item,
id: res('id').default(r.uuid()),
created_at: this.r.now()
},
{
returnChanges: true,
conflict: (id, old, new) =>
old.merge(item).merge({updated_at: this.r.now()})
}
)
))
.run()
此外,如果您需要执行它,我建议在 itemId 上创建二级索引并使用 "getAll" 而不是 "filter"。
如果您很有可能同时获得具有相同 itemId 的多个项目,这些方法将无济于事,要解决此问题,您需要创建一个不同的唯一 table:
r.table('products_itemId')
.insert(
{itemId: item.itemId, id: r.uuid()},
{ returnChanges: true, conflict: (id, old, new) => old }
)
.do(res =>
r.table('products').insert(
{
...item,
id: res('new_val')('id'),
created_at: this.r.now()
},
{
returnChanges: true,
conflict: (id, old, new) =>
old.merge(item).merge({updated_at: this.r.now()})
}
)
))
.run()
请注意,您必须手动维护对 itemId 字段的删除和更新
我有一个 .itemId
来自第三方,不是我生成的。
我需要在数据库中查找它,如果不存在则更新或插入它。
我试过使用食谱中的这个例子:https://www.rethinkdb.com/docs/cookbook/javascript/#manipulating-documents
const res = await this.r.table('products').filter({itemId: item.itemId})
.limit(1)
.replace(doc => {
return this.r.branch(
doc.eq(null),
this.r.expr(item).merge({created_at: this.r.now()}),
doc.merge(item).merge({updated_at: this.r.now()})
)
}, {
returnChanges: true
}).run(this.conn);
if (res.replaced) {
return res.changes[0].new_val;
} else {
return item; // doc was never inserted as everything in `res` is `0`.
}
res.changes
如果该文档不存在并且我在它不在数据库中后搜索它,则未定义。它从未被插入。
有没有办法简化给定任意 属性 对象的 upsert()
命令?
在 "else" 子句中,您应该执行插入查询,并且代码中的分支子句是无用的(查询永远不会 return "null" 因此项目不会 "created")
有几种方法可以解决这个问题: 最好的方法是使用 itemId(或 r.uuid(itemId))作为主键并使用冲突子句进行插入。
如果你不能 一种方法是尝试替换,如果没有替换任何内容,则插入:
this.r.table('products').filter({itemId: item.itemId})
.limit(1)
.replace(
doc => doc.merge(item).merge({updated_at: this.r.now()}),
{ returnChanges: true }
)
.do(res => res('replaced').eq(1).branch(
res,
r.table('products').insert(
{ ...item, created_at: this.r.now()},
{ returnChanges: true }
)
))
.run()
另一种方法是尝试查看是否存在并使用索引进行更新:
this.r.table('products').filter({itemId: item.itemId})
.nth(0)
.default(null)
.do(res =>
r.table('products').insert(
{
...item,
id: res('id').default(r.uuid()),
created_at: this.r.now()
},
{
returnChanges: true,
conflict: (id, old, new) =>
old.merge(item).merge({updated_at: this.r.now()})
}
)
))
.run()
此外,如果您需要执行它,我建议在 itemId 上创建二级索引并使用 "getAll" 而不是 "filter"。
如果您很有可能同时获得具有相同 itemId 的多个项目,这些方法将无济于事,要解决此问题,您需要创建一个不同的唯一 table:
r.table('products_itemId')
.insert(
{itemId: item.itemId, id: r.uuid()},
{ returnChanges: true, conflict: (id, old, new) => old }
)
.do(res =>
r.table('products').insert(
{
...item,
id: res('new_val')('id'),
created_at: this.r.now()
},
{
returnChanges: true,
conflict: (id, old, new) =>
old.merge(item).merge({updated_at: this.r.now()})
}
)
))
.run()
请注意,您必须手动维护对 itemId 字段的删除和更新