skip to Main Content

everyone!
I would be very grateful for your help, I am a beginner in working with MongoDB.
I have 2 classes

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "user")
public class User {
    @Transient
    public static final String USER_SEQUENCE = "user_sequence";
    @Id
    private Long id;
    private String username;
    private String password;
    private Set<Role> roles = new HashSet<>();
    @DBRef
    private List<Article> articles = new ArrayList<>();
}

and

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "articles")
public class Article {
    @Transient
    public static final String ARTICLE_SEQUENCE = "article_sequence";
    @Id
    private Long id;
    private String text;
    private int like = 0;
    @Setter(AccessLevel.NONE)
    private Set<Long> likedBy = new HashSet<>();
    @Setter(AccessLevel.NONE)
    private Set<Long> dislikedBy = new HashSet<>();
    @DBRef
    private User user;

    public Article(Long id, String text, User user) {
        this.id = id;
        this.text = text;
        this.user = user;
    }
}

I need to implement a method that will retrieve all articles by username
This is my implementation, but it doesn’t work(((

public interface ArticleRepository extends MongoRepository<Article, Long> {
    List<Article> findAllByOrderByIdDesc();

    @Aggregation(pipeline = {
            "{$lookup: {from: 'users', localField: 'user', foreignField: '_id', as: 'user'}}",
            "{$unwind: '$user'}",
            "{$match: {'user.username': ?0}}"
    })
    List<Article> findAllByUserUsername(String username);
}

Help me understand how to do this, please

Of course, I can pull out the User by name and take the gender from it, but I think it’s not right.

public interface UserRepository extends MongoRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

2

Answers


  1. On $lookup stage you’re trying to join on user field which is a DBRef in the articles collection and _id field in the users collection. The issue is that DBRef is a complex object, and you cannot directly compare it with the _id field.

    In MongoDB, a DBRef is a document that contains the following fields:

    {
       $ref : <collection name>,
       $id : <id>,
       $db : <database name>
    }
    

    Your User field in the Article collection would look something like this:

    {
        $ref : 'user',
        $id : <user_id>,
        $db : <database_name>
    }
    

    Thus, in your $lookup part, you should use user.$id as the localField instead of user:

    @Aggregation(pipeline = {
            "{$lookup: {from: 'user', localField: 'user.$id', foreignField: '_id', as: 'user'}}",
            "{$unwind: '$user'}",
            "{$match: {'user.username': ?0}}"
    })
    List<Article> findAllByUserUsername(String username);
    
    Login or Signup to reply.
  2. You can fetch only the list of articles from the User repository as follows:

    Keep your User class as is in your question.

    Remove @DBRef private User user; from your Article class.

    User Repository

    public interface UserRepository extends MongoRepository<User, Long> {
    
        @Query("select u.articles from User u where u.username:=username")
        List<Article> findArticlesbyUsername(@Param("username") String username);
    }
    

    This will fetch only the list of articles through your User class.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search