Saturday 27 May 2017

Query top level array of subdocs with MONGOOSE, to only return N most recent subdocuments in array

I'm looking for the conditions, fields, etc that i would need in a query, or an async flow to query a single document which has an array of subdocuments at the top-level.

Model:

let postSchema = new mongoose.Schema({
    date : {type: Boolean, require: true},
    message : {type: String, require: true}
});

let Post = new mongoose.Schema({
    locid: {type: String, unique: {indexed: true}, require: true},
    posts : {type: [postSchema], require: false}
});

Essentially, I would provide a Locid value as shown above into a function that i'm hoping would look like this:

Post.methods.getLastTwentyPostsForOne = function (locid) {
    return new Promise(function (values, error) {
        let p = new Post();
        p.find({"locid" : locid}, {/*...the conditions and elements here...*/}).exec()
            .then(function (found) {

                //..would return the last 20 posts, or less if there are less...

            }, function (err) {
                //..handle errors..
            })
    })
};

The most basic way i can think of doing this, would be to just fetch the whole array, and since mongo stores entries one after the other chronologically, to just parse the array and appending the last 20 or less posts contained in it into a final array (with a second promise-based function).

this makes the previous method, look like this:

function returnLastTwenty(posts) {
    return new Promise(function (results) {
        if (posts.length === 0) {
            return results([]);
        }
        if (posts.length <= 20) {
            return results(posts);
        }
        let length = posts.length;
        var next = [];
        for (i = length - 21; i < (length -1); i++) {
            next.append(posts[i]);
        }
        if (next.length === 20) {
            return results(next);
        } else {
            console.log('Some Error: found more than 20 posts, but parsed less');
            return results(next)
        }
    });
}

Post.methods.getLastTwentyPostsForOne = function (locid) {
    return new Promise(function (values, error) {
        let p = new Post();
        p.find({"locid" : locid})
            .then(function (found) {
                if (found.length === 1) {
                    returnLastTwenty(found[0].posts)
                        .then(function (results) {
                            return values(results)
                        })
                } else {
                    return error("Didn't find a unique document for locid: " + locid);
                }
            }, function (err) {
                return error(err)
            })
    })
};

While this does work.. the for loop and second async method seems too much.. Any clues as to how to achieve this with mongoose with a single query?



via murphguy

No comments:

Post a Comment