Note that there are some explanatory texts on larger screens.

plurals
  1. POMongoDB 'upsert' from Grails
    primarykey
    data
    text
    <p>I'm trying to implement a simple "insert or update" (so-called 'upsert') method in Grails / GORM / mongodb plug-in / MongoDB. </p> <p>The approach I used with Hibernate (using merge) fails with a duplicate key error. I presume perhaps merge() isn't a supported operation in mongodb GORM, and tried to get to the native upsert method through GMongo.</p> <p>I finally have a version that works (as posted below), but it is probably not the best way, as adding any fields to the object being saved will break the code silently.</p> <pre><code> 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) } */ } </code></pre> <p>I guess I could introduce another POJO-DbObject mapping framework to the mix, but that would complicate things even more, duplicate what GORM is already doing and may introduce additional meta-data.</p> <p>Any ideas how to solve this in the simplest fashion? </p> <p>Edit #1: I now tried something else:</p> <pre><code> 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) } </code></pre> <p>Once again the non-commented version works, but is not well maintainable. The commented version which I'd like to make work fails.</p> <p>Edit #2: </p> <p><strong>Version which works</strong>:</p> <pre><code>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) } </code></pre> <p>Version which never seems to insert anything:</p> <pre><code>def upsertPrefix(Prefix updatedPrefix) { Prefix existingPrefix = Prefix.findOrCreateById(updatedPrefix.id) updatedPrefix.properties.each { prop -&gt; 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 } </code></pre> <p>Version which still fails with duplicate key error:</p> <pre><code>def upsertPrefix(p) { def existing = Prefix.get(p.id) if (existing != null) { p.properties.each { prop -&gt; 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) } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload