Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Mongodb pagination of nested collection field

I have a collection of document inside another document. Would like to implement pagination on nested element while fetching the data. Could you please let me know how to do that? In the structure I would like to fetch messages using pagination.

public abstract class CommonDomainAttributes implements Serializable, Cloneable {
    private static final long serialVersionUID = 1L;

    @Id
    protected String id;

    @JsonIgnore
    @CreatedDate
    protected Date createDate;

    //@JsonIgnore
    @LastModifiedDate
    //@JsonSerialize(using=JsonDateSerializer.class)
    protected Date lastModifiedDate;

    @JsonIgnore
    @CreatedBy
    protected String createdBy;

    @JsonIgnore
    @LastModifiedBy
    protected String lastModifiedBy;
    /**
     * @return the id
     */
    public String getId() {
        return id;
    }
    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }
    /**
     * @return the createDate
     */
    public Date getCreateDate() {
        return createDate;
    }
    /**
     * @param createDate the createDate to set
     */
    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }
    /**
     * @return the lastModifiedDate
     */
    public Date getLastModifiedDate() {
        return lastModifiedDate;
    }
    /**
     * @param lastModifiedDate the lastModifiedDate to set
     */
    public void setLastModifiedDate(Date lastModifiedDate) {
        this.lastModifiedDate = lastModifiedDate;
    }
    /**
     * @return the createdBy
     */
    public String getCreatedBy() {
        return createdBy;
    }
    /**
     * @param createdBy the createdBy to set
     */
    public void setCreatedBy(String createdBy) {
        this.createdBy = createdBy;
    }
    /**
     * @return the lastModifiedBy
     */
    public String getLastModifiedBy() {
        return lastModifiedBy;
    }
    /**
     * @param lastModifiedBy the lastModifiedBy to set
     */
    public void setLastModifiedBy(String lastModifiedBy) {
        this.lastModifiedBy = lastModifiedBy;
    }
    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (id == null ? 0 : id.hashCode());
        return result;
    }
    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        CommonDomainAttributes other = (CommonDomainAttributes) obj;
        if (id == null) {
            if (other.id != null) {
                return false;
            }
        } else if (!id.equals(other.id)) {
            return false;
        }
        return true;
    }




    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("CommonDomainAttributes [id=").append(id)
        .append(", createDate=").append(createDate)
        .append(", lastModifiedDate=").append(lastModifiedDate)
        .append(", createdBy=").append(createdBy)
        .append(", lastModifiedBy=").append(lastModifiedBy)
        .append(", toString()=").append(super.toString()).append("]");
        return builder.toString();
    }


}

public class Message extends CommonDomainAttributes implements Serializable{

    private String fromuserId;
    private String fromuserName;
    private String toUserId;
    private String touserName;
    private String message;
    /**
     * @return the fromuserId
     */
    public String getFromuserId() {
        return fromuserId;
    }
    /**
     * @param fromuserId the fromuserId to set
     */
    public void setFromuserId(String fromuserId) {
        this.fromuserId = fromuserId;
    }
    /**
     * @return the fromuserName
     */
    public String getFromuserName() {
        return fromuserName;
    }
    /**
     * @param fromuserName the fromuserName to set
     */
    public void setFromuserName(String fromuserName) {
        this.fromuserName = fromuserName;
    }
    /**
     * @return the toUserId
     */
    public String getToUserId() {
        return toUserId;
    }
    /**
     * @param toUserId the toUserId to set
     */
    public void setToUserId(String toUserId) {
        this.toUserId = toUserId;
    }
    /**
     * @return the touserName
     */
    public String getTouserName() {
        return touserName;
    }
    /**
     * @param touserName the touserName to set
     */
    public void setTouserName(String touserName) {
        this.touserName = touserName;
    }
    /**
     * @return the message
     */
    public String getMessage() {
        return message;
    }
    /**
     * @param message the message to set
     */
    public void setMessage(String message) {
        this.message = message;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Message [fromuserId=");
        builder.append(fromuserId);
        builder.append(", fromuserName=");
        builder.append(fromuserName);
        builder.append(", toUserId=");
        builder.append(toUserId);
        builder.append(", touserName=");
        builder.append(touserName);
        builder.append(", message=");
        builder.append(message);
        builder.append(", toString()=");
        builder.append(super.toString());
        builder.append("]");
        return builder.toString();
    }
}

@Document(collection="discussion")
@TypeAlias("discussion")
public class Discussion extends CommonDomainAttributes implements Serializable{

    private String discussionTopic;
    private List<Message> messages;
    /**
     * @return the discussionTopic
     */
    public String getDiscussionTopic() {
        return discussionTopic;
    }
    /**
     * @param discussionTopic the discussionTopic to set
     */
    public void setDiscussionTopic(String discussionTopic) {
        this.discussionTopic = discussionTopic;
    }
    /**
     * @return the messages
     */
    public List<Message> getMessages() {
        return messages;
    }
    /**
     * @param messages the messages to set
     */
    public void setMessages(List<Message> messages) {
        this.messages = messages;
    }


    /**
     * @param messages the messages to set
     */
    public void addMessages(Message message) {
        if(null == messages){
            messages = new LinkedList<>();
        }
        messages.add(message);
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Discussion [discussionTopic=");
        builder.append(discussionTopic);
        builder.append(", messages=");
        builder.append(messages);
        builder.append(", toString()=");
        builder.append(super.toString());
        builder.append("]");
        return builder.toString();
    }

}
like image 588
Debopam Avatar asked May 12 '16 18:05

Debopam


1 Answers

A bit on Mongo Query Language


In MongoDB, the $slice operator controls the number of items of an array that a query returns. The $slice operator can accept values with following syntax:

[toSkip, toLimit]

Where the first value indicates the number of items in the array to skip and the second value indicates the number of items to return. For example, you can use the following query:

db.discussions.find({}, {messages: {$slice: [20, 10]}})

To return 10 messages, after skipping the first 20 messages of that array.

Bring it to Spring Data World


In order to use $slice operator with Spring Data MongoDB, you should use @Query annotation and its fields attribute. For example, if you have a DiscussionRepository, you could write something like:

public interface DiscussionRepository extends MongoRepository<Discussion, String> {
    @Query(value = "{}", fields = "{messages: {$slice: [?0, ?1]}}")
    List<Discussion> findDiscussions(int skip, int limit);
}

With this arrangement, following method call:

discussionRepository.findDiscussions(20, 10)

Would generate the same result as:

db.discussions.find({}, {messages: {$slice: [20, 10]}})

With a little bit of work, you can turn the Skip/Limit combination to a pagination functionality.

like image 171
Ali Dehghani Avatar answered Sep 20 '22 07:09

Ali Dehghani