2

I'm using Morphia 0.99 and I'm trying to update an embedded field in an entity, but I don't see how.

// User entity
@Entity(value = "users", noClassnameStored = true)
public class User
{
    @Id
    private String id;

    @Embedded
    private UserConfig userConfig;
}

// User DAO
public class UserDao extends BasicDAO <User, ObjectId> implements IUserDao
{
    @Override
    public void setConfig (String userId, UserConfig config)
    {
        User user = get (new ObjectId (userId));
        user.setNotificationsTypes (notitypes);
        "this.update(user);"
    }
}

This page suggests something this:

// User DAO
public class UserDao extends BasicDAO <User, ObjectId> implements IUserDao
{
    @Override
    public void setConfig (String userId, UserConfig config)
    {
        Query <User> query = ds.createQuery (User.class).field (idString).equal (userId);
        UpdateOperations <User> ops = ds.createUpdateOperations (User.class).set ("userConfig.someField", "Some Value");
        ds.update (updateQuery, ops);
    }
}

But I want to update the whole embedded field, not each subfield one by one. How can I do that? Thanks!

Marc
  • 16,170
  • 20
  • 76
  • 119
NaBUru38
  • 99
  • 1
  • 7
  • Either use an update on a specific field (or multiple ones) or persist the whole object again (in your case on the User class) - persist will do an upsert. – xeraa Nov 06 '12 at 16:47
  • But what is the code for that? These two didn't work: Query query = ds.createQuery(User.class).field (idString).equal (userId); UpdateOperations ops = ds.createUpdateOperations (User.class) .set ("userConfig.field1", value1) .set ("userConfig.field2", value2) ds.update (query, ops); – NaBUru38 Nov 06 '12 at 17:12
  • The other option that didn't work is: UpdateOperations ops = ds.createUpdateOperations (User.class).set ("userConfig", config); ds.update (query, ops); – NaBUru38 Nov 06 '12 at 17:16
  • ``ds.save(user);`` - if ``user._id`` is empty a new document will be created (and the database will generate your ID), if there is an ID the document with it will be updated. – xeraa Nov 06 '12 at 18:01
  • That doesn't work. I tried this code: User user = get (new ObjectId (userId)); user.setUserConfig (config); this.save (user); When I execute that, I get this Error E11000: duplicate error index: mydb.users.$username_1 dup key: {: "Andrew"} Andrew is the test username, which is a unique attribute of User. – NaBUru38 Nov 06 '12 at 18:08
  • Somewhat is off with your ``_id``. You should use ``ObjectId`` for ``@Id`` in general, but for this scenario a string should work as well. Are you sure ``new ObjectId (userId)`` is behaving as you expect? – xeraa Nov 06 '12 at 19:08
  • Don't ask me why, but we have been using String in all entities and ObjectId in the DAOs. T tried to convert the UserDao from to , but the this.get() method stopped working. I'll try to change the entity to ObjectId. But how will I use the class outside the server, where there's no Morphia? I think that's the reason why we use String for the identifiers. – NaBUru38 Nov 06 '12 at 21:53
  • I can't change the entity to ObjectId, it breaks several other pieces of code. There must be a solution with the current scheme. – NaBUru38 Nov 06 '12 at 22:01
  • Let's go back to square one. Since I'll show the actual log, I'll paste the actual code I tried to execute: /**/ Query query = ds.createQuery(User.class).field (idString).equal (userId); UpdateOperations ops = ds.createUpdateOperations(User.class).set ("notificationsTypes", notitypes); ds.update (query, ops); /**/ – NaBUru38 Nov 06 '12 at 23:02
  • The Mongo log says this: /**/ { "ts" : ISODate("2012-11-06T22:56:31.477Z"), "op" : "update", "ns" : "geouy.users", "query" : { "_id" : "50998e930000bc3b6d20bf5a" }, "updateobj" : { "$set" : { "notificationsTypes" : { "notitype1_contactsVisits" : true, "notitype2_contactsComments" : false } } }, "nscanned" : 0, "nupdated" : 0, "keyUpdates" : 0, "numYield" : 0, "lockStats" : { "timeLockedMicros" : { "r" : NumberLong(0), "w" : NumberLong(126) }, "timeAcquiringMicros" : { "r" : NumberLong(0), "w" : NumberLong(9) } }, "millis" : 0, "client" : "192.168.2.2", "user" : "" }/**/ – NaBUru38 Nov 06 '12 at 23:04
  • The values of the user are these: /**/ { "_id" : ObjectId("50998e930000bc3b6d20bf5a"), "userName" : "Agustin", "notificationsTypes" : { "notitype1_contactsVisits" : false, "notitype2_contactsComments" : false, "roles" : [ "REG_USER" ] } /**/ So I tried to set notitype1_contactsVisits to true, but the entre remains at false. As you can see, the id is the same. What's the issue? – NaBUru38 Nov 06 '12 at 23:05
  • I found the answer: I had to type "equal (new ObjectId (userId))". So Morphia isn't that much type safe :) Thanks for the help! – NaBUru38 Nov 06 '12 at 23:31
  • Actually it is: ``"_id" : "50998e930000bc3b6d20bf5a"`` != ``"_id" : ObjectId("50998e930000bc3b6d20bf5a")`` We are using ObjectIds for internal use and an additional, unique UUID which is exposed externally – xeraa Nov 06 '12 at 23:38
  • Morphia's query system allowed me to try to compare an ObjectId with a String. It didn't show a compile error or throw a runtime error, the query resulted in a no match. That's what I mean by saying Morphia isn't type-safe. Bye! – NaBUru38 Nov 07 '12 at 18:53

0 Answers0