close

Filter

Elastic Social Manual / Version 2406.0

Table Of Contents

4.2 Persistence Model

The Elastic Core persistence is based on instances of Models to which the data that is stored in MongoDB is mapped at runtime. The idea is that not the Java classes determine how the MongoDB documents are structured but the MongoDB document is mapped to a given Java instance. Parts of the documents that do not fit the given Java instance are mapped into a generic data pool to make sure that no data is lost when the Java instance is persisted back into the MongoDB document just because the given Java instance does not understand them:

Mapping of Java classes and MongoDB documents

Figure 4.1. Mapping of Java classes and MongoDB documents


This mapping behavior offers a lot more flexibility to update Java classes without running into the hassles of schema evolution. For example, it allows for different Model classes accessing the same data at the same time. But it is different from typical mappers like Morphia, Spring Data for MongoDB or Hibernate that take a Java class as the source how to structure the data in the storage underneath.

Mapping properties

The mapping algorithm uses Java Bean properties as entities to load and store data. That means if some Model class is used to load data via for example the ModelService get(...) methods, the Query or the SearchService, the mapping algorithm first creates an instance of the given Model class and then calls the setters of the instance to transfer data from the MongoDB document to the instance. If a Java Bean property is defined in the Model instance, its setter method is called by the mapping algorithm and its value is accessible via the getter method. If no Java Bean property is defined the data is stored in the generic data pool of the instance, which is accessible via Model#getProperty().

If an instance of a Model class is stored with Model#save() or ModelService#save(), the mapping algorithm calls the getters of the given instance and joins them with the generic data pool to map these properties into a MongoDB document. The key for storing of data is the same combination of ID and Collection that was used to lookup the data.

In all implementations of this interface all setter methods for non-primitive types must support null values, even if a default value is used during initialization. Code or data migration might still cause the setter to be called with a null value.

Mapping atomic values

The following table describes the mapping of BSON values to the corresponding Java types:

BSON Java
Boolean false/true Boolean
Floating point double
32-bit Integer int
64-bit Integer long
Boolean false/true java.lang.Boolean
UTC date time java.util.Date
Floating point java.lang.Double
32-bit Integer java.lang.Integer
64-bit Integer java.lang.Long
UTF-8 string java.lang.String
Object ID org.bson.types.ObjectId

Table 4.1. Mapping of BSON values to Java types


Mapping collection values

The following table describes the mapping of BSON collection values to the corresponding Java types:

BSON Java
Array java.util.List
Embedded document java.util.Map

Table 4.2. Mapping of BSON collection values to Java types


Please note that the mapping is defined from BSON values to Java types which means that you are limited to java.util.List and java.util.Map and cannot use the full expressiveness of the Java collection framework.

Mapping references

References to other Models or user defined classes are supported via TypeConverters.

To make the implementation of custom TypeConverters easier, the helper class AbstractTypeConverter is there to provide a basic implementation for user defined types. For Models there is a specialized AbstractModelConverter that provides a basic implementation for user defined Models.

The following table describes which Maven module contains support for the given types:

Module Mapped Class
core-impl com.coremedia.elastic.core.api.blobs.Blob
  com.coremedia.elastic.core.api.models.Model
  com.coremedia.elastic.core.api.users.User
  java.lang.Enum
  java.lang.Locale
social-impl com.coremedia.elastic.social.api.comments.Comment
  com.coremedia.elastic.social.api.reviews.Review
  com.coremedia.elastic.social.api.users.CommunityUser
core-cms com.coremedia.cap.content.Content
  com.coremedia.objectserver.beans.ContentBean
  com.coremedia.xml.Markup

Table 4.3. Which module contains support for which type


MongoDB Collections and IDs

MongoDB documents are stored in collections which can be seen as named groupings of documents which share roughly the same structure or purpose. Indexes and queries are defined per MongoDB collection. The key for the lookup of data in the MongoDB is the combination of ID and Collection. It is accessible via Model#getId() and Model#getCollection().

Extending models, users and comments

The basic idea to extend Models is to keep it simple for the API user, but hide and reuse the implementation. You should never extend internal subclasses. Extending public interfaces is possible and supported but not necessary. If you want to extend the API interfaces, create an interface and an implementation for that aspect you are missing like this:

public interface FooUser extends User {
  String getFoo();
  void setFoo(String foo);
}

public abstract class FooUserImpl implements FooUser {
  private String foo;

  public String getFoo() {
    return foo;
  }

  public void setFoo(String foo) {
    this.foo = foo;
  }
}

        

Example 4.1. Extending the API interfaces


Instances of the class above are enhanced with the internal implementation of Model and User when calling UserService#createUser(). Beware that this call does not persist the returned instance to give the caller a possibility to modify the returned instance before saving it with Model#save().

FooUser fooUser = userService.createUser("foos-id", FooUserImpl.class);
fooUser.setFoo("foo");
fooUser.save();

        

Example 4.2. Modifying returned instance


When you already have a User, just use UserService#createFrom() to turn it into FooUser with a copy of the data that the User had. All data from User is still readable and writable through the methods for the generic data pool:

User user = userService.getUserById("4711");
FooUser fooUser = userService.createFrom(user, FooUserImpl.class);
fooUser.setFoo("bar");
fooUser.setProperty("name", "Foobar");
fooUser.save();

        

Example 4.3. Create user from existing user


Note

Note

user and fooUser are different instances. Any changes to user are not visible at the fooUser instance. Saving a modified user and then a modified fooUser in the scenario above will overwrite the changes applied to user.

Changing the class of an instance

ModelService#createFrom may be used to change the class for a given Model instance without reloading the data from the underlying MongoDB document.

Search Results

Table Of Contents
warning

Your Internet Explorer is no longer supported.

Please use Mozilla Firefox, Google Chrome, or Microsoft Edge.