gpt4 book ai didi

来自 Grails 的 MongoDB 'upsert'

转载 作者:可可西里 更新时间:2023-11-01 10:44:37 25 4
gpt4 key购买 nike

我正在尝试在 Grails/GORM/mongodb 插件/MongoDB 中实现一个简单的“插入或更新”(所谓的“upsert”)方法。

我在 Hibernate 中使用的方法(使用合并)因重复键错误而失败。我推测 merge() 可能不是 mongodb GORM 中受支持的操作,并尝试通过 GMongo 获取 native 更新插入方法。

我终于有了一个可用的版本(如下所示),但这可能不是最好的方法,因为向要保存的对象添加任何字段都会悄无声息地破坏代码。

 public void upsertPrefix(p) {
def o = new BasicDBObject()
o.put("_id", p.id)
o.put("someValue", p.someValue)
o.put("otherValue", p.otherValue)

// DBObject o = p as DBObject // No signature of method: mypackage.Prefix.keySet() is applicable for argument types: () values: []

db.prefix.update([_id : p.id], o, true, false)
// I actually would want to pass p instead of o here, but that fails with:
// No signature of method: com.gmongo.internal.DBCollectionPatcher$__clinit__closure2.doCall() is applicable for argument types: (java.util.ArrayList) values: [[[_id:keyvalue], mypackage.Prefix : keyvalue, ...]]


/* All of these other more "Hibernatesque" approaches fail:
def existing = Prefix.get(p.id)
if (existing != null) {
p.merge(flush:true) // E11000 duplicate key error
// existing.merge(p) // Invocation failed: Message: null
// Prefix.merge(p) // Invocation failed: Message: null

} else {
p.save(flush:true)
}
*/
}

我想我可以引入另一个 POJO-DbObject 映射框架,但这会使事情变得更加复杂,重复 GORM 已经在做的事情并可能引入额外的元数据。

有什么想法可以用最简单的方式解决这个问题吗?

编辑#1:我现在尝试了其他东西:

    def existing = Prefix.get(p.id)
if (existing != null) {
// existing.properties = p.properties // E11000 duplicate key error...
existing.someValue = p.someValue
existing.otherValue = p.otherValue
existing.save(flush:true)
} else {
p.save(flush:true)
}

再一次,非注释版本可以工作,但维护性不佳。我想使工作的评论版本失败。

编辑#2:

有效的版本:

public void upsertPrefix(p) {
def o = new BasicDBObject()

p.properties.each {
if (! (it.key in ['dbo'])) {
o[it.key] = p.properties[it.key]
}
}
o['_id'] = p.id

db.prefix.update([_id : p.id], o, true, false)
}

似乎从不插入任何内容的版本:

def upsertPrefix(Prefix updatedPrefix) {
Prefix existingPrefix = Prefix.findOrCreateById(updatedPrefix.id)
updatedPrefix.properties.each { prop ->
if (! prop.key in ['dbo', 'id']) { // You don't want to re-set the id, and dbo is r/o
existingPrefix.properties[prop.key] = prop.value
}
}
existingPrefix.save() // Never seems to insert anything
}

仍然因重复键错误而失败的版本:

def upsertPrefix(p) {
def existing = Prefix.get(p.id)
if (existing != null) {
p.properties.each { prop ->
print prop.key
if (! prop.key in ['dbo', 'id']) {
existingPrefix.properties[prop.key] = prop.value
}
}
existing.save(flush:true) // Still fails with duplicate key error
} else {
p.save(flush:true)
}
}

最佳答案

假设您拥有对象的更新版本,或者需要使用新值更新的属性映射,您可以遍历这些对象并为每个属性应用更新。

像这样:

def upsert(Prefix updatedPrefix) {
Prefix existingPrefix = Prefix .findOrCreateById(updatedPrefix.id)
updatedPrefix.properties.each { prop ->
if (prop.key != 'id') { // You don't want to re-set the id
existingPrefix.properties[prop.key] = prop.value
}
}
existingPrefix.save()
}

如何排除更新 ID 可能不太正确,因此您可能需要尝试一下。如果相应的新值与现有值不同,您也可能只考虑更新属性,但这本质上只是一种优化。

如果您有 map ,您也可以考虑按照默认 Controller 脚手架的方式进行更新:

prefixInstance.properties = params

关于来自 Grails 的 MongoDB 'upsert',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11784087/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com