Skip to content

Populating with perDocumentLimit multiplies common entries #9906

@paulholleis

Description

@paulholleis

Do you want to request a feature or report a bug?
I think it's a bug with perDocumentLimit.

What is the current behavior?
Have 2 objects of the same Model M with each an array M.arr; both arrays have an entry that ref the same object X.
When populating with perDocumentLimit, I get, instead of just the populated X object, an array [X, X] within M.arr

If the current behavior is a bug, please provide the steps to reproduce.
This is the 9175.js with an added commonComment that is added to both Posts.
The script runs perfectly well without perDocumentLimit.

const mongoose = require('mongoose');

const { Schema } = mongoose;
const assert = require('assert');

async function createFirstPost(Post, Comment, commonComment) {
    const post = new Post({ title: 'I have 3 comments' });

    const comment1 = new Comment({ content: 'Cool first post' });
    const comment2 = new Comment({ content: 'Very cool first post' });
    const comment3 = new Comment({ content: 'Super cool first post' });

    post.commentsIds = [commonComment, comment1, comment2, comment3].map((comment) => comment._id);
    await Promise.all([
        post.save(),
        comment1.save(),
        comment2.save(),
        comment3.save(),
    ]);
}

async function createSecondPost(Post, Comment, commonComment) {
    const post = new Post({ title: 'I have 4 comments' });

    const comment1 = new Comment({ content: 'Cool second post' });
    const comment2 = new Comment({ content: 'Very cool second post' });
    const comment3 = new Comment({ content: 'Super cool second post' });
    const comment4 = new Comment({ content: 'Absolutely cool second post' });

    post.commentsIds = [commonComment, comment1, comment2, comment3, comment4].map((comment) => comment._id);
    await Promise.all([
        post.save(),
        comment1.save(),
        comment2.save(),
        comment3.save(),
        comment4.save(),
    ]);
}

async function run() {
    await mongoose.connect('mongodb://localhost:27017/test', {
        useNewUrlParser: true,
        useUnifiedTopology: true,
    });

    await mongoose.connection.dropDatabase();

    const postSchema = new Schema({
        title: String,
        commentsIds: [{ type: Schema.ObjectId, ref: 'Comment' }],
    });
    const Post = mongoose.model('Post', postSchema);

    const commentSchema = new Schema({ content: String });
    const Comment = mongoose.model('Comment', commentSchema);

    const commonComment = new Comment({ content: 'Im used in two posts' });
    await commonComment.save();
    await createFirstPost(Post, Comment, commonComment);
    await createSecondPost(Post, Comment, commonComment);

    const posts = await Post.find().populate({ path: 'commentsIds', perDocumentLimit: 2 });

    console.log(JSON.stringify(posts[0]));

    // first comment should not be an array but is [commonComment, commonComment]
    assert.notEqual(posts[0].commentsIds[0].length, 2);

    assert.equal(posts[0].commentsIds.length, 2);
    assert.equal(posts[1].commentsIds.length, 2);

    console.log('All assertions passed.');
}

run().catch(console.error);

This produces

{
  "commentsIds":
    [
        [**
           {"_id":"6021493f067381d74303df02","content":"Im used in two posts","__v":0},**
           {"_id":"6021493f067381d74303df02","content":"Im used in two posts","__v":0}**
        ]**,
        {"_id":"6021493f067381d74303df04","content":"Cool first post","__v":0}
    ],
  "_id":"6021493f067381d74303df03","title":"I have 3 comments","__v":0
}

What is the expected behavior?
It should include the commonComment only once and not an array of two commonComments.

What are the versions of Node.js, Mongoose and MongoDB you are using? Note that "latest" is not a version.
Node: v14.15.1
Mongoose: 5.11.15
MongoDB: v4.2.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugWe've confirmed this is a bug in Mongoose and will fix it.has repro scriptThere is a repro script, the Mongoose devs need to confirm that it reproduces the issue

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions