0

I can't really figure out how to return nested fields within array of objects. Here is my schema:

const chat = new Schema({
    id: {
        type: String,
        required: true
    },
    channels: [
        {
            id: {
                type: String
            },
            messages: [
                {
                    author: String,
                    body: String,
                    created_at: Date,
                    _id: false,
                    avatar: String
                }
            ]
        }
    ]

})

I want to receive 50 channel messages by using chat ID and channel ID from specific range provided by user (0-49, 50-99 and so on).

So in the end I receive array of objects from that channel.

const messages = [{...}, {...}, ...]

2 Answers 2

1

Just a different variation of the first answer to actually return ONLY the required channel and not all of them.

db.getCollection("collection").aggregate(
    [
        { 
            "$match" : {
                "id" : chatid
            }
        }, 
        { 
            "$unwind" : "$channels"
        }, 
        { 
            "$match" : {
                "channels.id" : channelid
            }
        }, 
        { 
            "$project" : {
                "messages" : {
                    "$slice" : [
                        "$channels.messages", 
                        0.0, 
                        50.0
                    ]
                }
            }
        }
    ]
);
Sign up to request clarification or add additional context in comments.

1 Comment

Good catch tom, I edited my answer to reflect the additional match, but I like your use of slicing in the project stage 👍
1

I'd use the aggregation pipeline for this. I haven't used mongoose but for a basic mongo query it'd look like:

db.getCollection("collection").aggregate(
    [
        { 
            //find the matching documents
            "$match" : {
                "id" : "chatid", 
                "channels.id" : "channelid"
            }
        }, 
        { 
            //split the document into the individual messages
            "$unwind" : "$channels.messages"
        },
        { 
            "$match" : {
                "channels.id" : "channelid"
            }
        }, 
        {
            //limit to 50 (can be after the project stage)
            "$limit" : 50
        }, 
        { 
            //update to just return the message subdoc
            "$replaceRoot" : {
                "newRoot" : "$channels.messages"
            }
        }
    ]
);

For mongoose check the aggregation API or aggregation middleware docs to implement this

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.