Question

I have been playing around with Morphia as I had issues with working with referenced documents using Spring Data for Mongodb. Below are snapshots of the data I have and the code...

Here are my User and Group classes (getters and setters omitted)

User Class

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.mongodb.morphia.annotations.Entity;
import org.mongodb.morphia.annotations.Id;
import org.mongodb.morphia.annotations.Reference;



@Entity(value="users")
public class User {

@Id
    private String id;
private String username;
private String firstname;
private String lastname;
private String email;
private long cellnumber;
private Date datejoined;
private boolean active;
private Account account;

@Reference(value="usergroups", lazy=true)
private List<Group> usergroups = new ArrayList<>();

}

The group class.

@Entity(value="groups")
public class Group {
@Id
private String id;
private String name;
private String description;
private long creationdate;

@Reference
private User user;

}

I am now running the following methods, named scenario1() and scenario2() in a main method.

    private void scenario1() {

    User newUser = setupUser(new User());
    datastore.save(newUser);
    Query<User> query = datastore.createQuery(User.class)
            .field("firstname").equal("Jome");
    User user = query.get();

    Account account = new Account();
    account.setBalance(0.0);
    account.setSmsvalue(0.18);

    UpdateOperations<User> update = datastore
            .createUpdateOperations(User.class);
    update.set("account", account);

    user.setAccount(account);
    datastore.save(user);
    List<Group> groups = query.get().getUsergroups();

    Group group1 = new Group();
    group1.setCreationdate(new Date().getTime());
    group1.setDescription("test group for first user");
    group1.setName("Group One");
    group1.setUser(query.get());
    datastore.save(group1);
    groups.add(group1);
    update.add("usergroups", group1);
    datastore.update(query, update);

    Group group2 = new Group();
    group2.setCreationdate(new Date().getTime());
    group2.setDescription("Another test group for first user");
    group2.setName("Group Two");
    group2.setUser(query.get());
    datastore.save(group2);
    groups.add(group2);

    update.add("usergroups", group2);

    datastore.update(query, update);

    System.out.println(user);
    List<Group> savedgroups = user.getUsergroups();
    System.out.println(savedgroups);
}

And this is the output

User [id=52e8894ef148a7f866b9f1ac, username=jomski2013, firstname=Jome, lastname=Akpoduado, email=jomea@yookos.com, cellnumber=123456789]
[Group [id=52e8894ef148a7f866b9f1ad, name=Group One, description=test group for first user, creationdate=1390971214880, owner=User [id=52e8894ef148a7f866b9f1ac, username=jomski2013, firstname=Jome, lastname=Akpoduado, email=jomea@example.com, cellnumber=123456789]], Group [id=52e8894ef148a7f866b9f1ae, name=Group Two, description=Another test group for first user, creationdate=1390971214884, owner=User [id=52e8894ef148a7f866b9f1ac, username=jomski2013, firstname=Jome, lastname=Akpoduado, email=jomea@example.com, cellnumber=123456789]]]

and the view from the mongo console

> db.users.find().pretty()
{
"_id" : ObjectId("52e8894ef148a7f866b9f1ac"),
"account" : {
    "balance" : 0,
    "smsvalue" : 0.18
},
"active" : true,
"cellnumber" : NumberLong("123456789"),
"className" : "org.imanmobile.sms.core.domain.User",
"datejoined" : ISODate("2014-01-29T04:53:34.746Z"),
"email" : "jomea@example.com",
"firstname" : "Jome",
"lastname" : "Akpoduado",
"password" : "$2a$10$c0SAy7eJZv06eqmAWQNUP.YrXtB7tDOdi11lkZqlAVgzVGU9RCbCS",
"usergroups" : [
    DBRef("groups", "52e8894ef148a7f866b9f1ad"),
    DBRef("groups", "52e8894ef148a7f866b9f1ae")
],
"username" : "jomski2013"
}

> db.groups.find().pretty()
{
"_id" : ObjectId("52e8894ef148a7f866b9f1ad"),
"className" : "org.imanmobile.sms.core.domain.Group",
"name" : "Group One",
"description" : "test group for first user",
"creationdate" : NumberLong("1390971214880"),
"user" : DBRef("users", "52e8894ef148a7f866b9f1ac")
}
{
"_id" : ObjectId("52e8894ef148a7f866b9f1ae"),
"className" : "org.imanmobile.sms.core.domain.Group",
"name" : "Group Two",
"description" : "Another test group for first user",
"creationdate" : NumberLong("1390971214884"),
"user" : DBRef("users", "52e8894ef148a7f866b9f1ac")
}

However, when I subsequently run scenario2() below

    private void scenario2() {
    Query<User> query = datastore.createQuery(User.class);

    User user = query.field("username").equal("jomski2013").get();
    System.out.println("Number of groups: " + user.getUsergroups().size());
}

I get the error...

Caused by: org.mongodb.morphia.mapping.MappingException: The reference({ "$ref" : "groups", "$id" : "52e8894ef148a7f866b9f1ad" }) could not be fetched for org.imanmobile.sms.core.domain.User.usergroups
at org.mongodb.morphia.mapping.ReferenceMapper.resolveObject(ReferenceMapper.java:304)
at org.mongodb.morphia.mapping.ReferenceMapper$1.eval(ReferenceMapper.java:243)
at org.mongodb.morphia.utils.IterHelper.loopOrSingle(IterHelper.java:89)
at org.mongodb.morphia.mapping.ReferenceMapper.readCollection(ReferenceMapper.java:239)
at org.mongodb.morphia.mapping.ReferenceMapper.fromDBObject(ReferenceMapper.java:163)
at org.mongodb.morphia.mapping.Mapper.readMappedField(Mapper.java:602)
at org.mongodb.morphia.mapping.Mapper.fromDb(Mapper.java:584)
at org.mongodb.morphia.mapping.Mapper.fromDBObject(Mapper.java:294)
at org.mongodb.morphia.query.MorphiaIterator.convertItem(MorphiaIterator.java:71)
at org.mongodb.morphia.query.MorphiaIterator.processItem(MorphiaIterator.java:58)
at org.mongodb.morphia.query.MorphiaIterator.next(MorphiaIterator.java:53)
at org.mongodb.morphia.query.QueryImpl.get(QueryImpl.java:408)
at org.imanmobile.sms.PlayClass.scenario2(PlayClass.java:35)
at org.imanmobile.sms.PlayClass.run(PlayClass.java:29)
at org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:644)

My question is why is Morphia able to fetch the groups that were saved the first time around but not subsequently? What's different or what should i really be looking out for or missing?

Was it helpful?

Solution

There is a type mismatch between the usergroups DBRef array and the documents these are referencing:

"usergroups" : [
    DBRef("groups", "52e82c05f148a7310a899a50"),
    DBRef("groups", "52e82c05f148a7310a899a4f")
]

The $ref.id are of type String

Whereas the _id in the groups collection are of type ObjectId:

"_id" : ObjectId("52e82c05f148a7310a899a4f")

and

"_id" : ObjectId("52e82c05f148a7310a899a50")

This is why the references could not be fetched.

You don't have to run a secondary query, this is done automatically by Morphia.

It's hard to determine the cause for this mismatch. Could it be that initially in your Java Group Class you had private String ObjectId; field, which had been used for insertion, and then later changed to private String id;?

In any case to fix this, you will have to wrap the $ref.id values inside usergroups array with an ObjectId to fix this:

"usergroups" : [
     DBRef("groups", ObjectId("52e82c05f148a7310a899a50")),
     DBRef("groups", ObjectId("52e82c05f148a7310a899a4f"))
]

You will also have to change your Group mapping accordingly (set the id property as ObjectId)

If you want to leave things as are (treat everything as Strings), just drop your database (I guess you are just experimenting), and start from fresh

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top