Grails / GORM /mongodbプラグイン/MongoDBに単純な「挿入または更新」(いわゆる「アップサート」)メソッドを実装しようとしています。
私がHibernateで使用したアプローチ(マージを使用)は、重複キーエラーで失敗します。おそらくmerge()はmongodb GORMでサポートされている操作ではないと思い、GMongoを介してネイティブのupsertメソッドにアクセスしようとしました。
私はついに動作するバージョンを手に入れました(以下に投稿)が、保存されているオブジェクトにフィールドを追加するとコードが黙って壊れてしまうため、おそらく最善の方法ではありません。
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)
}
}