Запросите массив вложенных документов верхнего уровня с помощью MONGOOSE, чтобы вернуть только N самых последних вложенных документов в массиве

Я ищу условия, поля и т. Д., Которые мне понадобятся в запросе, или асинхронный поток для запроса одного документа, который имеет массив вложенных документов на верхнем уровне.

Модель:

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}
});

По сути, я бы предоставил значение Locid, как показано выше, в функцию, которая, я надеюсь, будет выглядеть так:

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..
            })
    })
};

Самым простым способом, который я могу придумать, было бы просто извлечь весь массив, и, поскольку mongo хранит записи одну за другой в хронологическом порядке, просто проанализировать массив и добавить последние 20 или менее записей, содержащихся в нем, в окончательный вариант. массив (со второй функцией, основанной на обещаниях).

это делает предыдущий метод похожим на это:

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)
            })
    })
};

Хотя это работает... цикл for и второй асинхронный метод кажутся слишком сложными. Есть какие-нибудь подсказки относительно того, как добиться этого с помощью mongoose с помощью одного запроса?


Обновление - Ответ

Благодаря комментарию Ratan Kumar, следующее, казалось, помогло.

function getPosts(amount, asOfIndex, locid) {
    return new Promise(function (posts, none) {
        Post.find({'locid' : locid},
            {'posts' :
                {"$slice" : [asOfIndex, amount]}
            }
        )
            .exec()
            .catch(function (err) {
                return none(err);
            })
            .then(function (found) {
                if (found.length === 0 || found.length > 1) return none(); //This can be changed for more specific error handling
                return posts(found[0].posts);
            });
    });
}

С индексом, являющимся произвольным числом, переданным через. Это может быть индекс из вызова API и т. Д. Где asOfIndex должен быть отрицательным, чтобы срезаться снизу массива, и положительным сверху ( https://docs.mongodb.com/manual/reference/operator/projection/slice/). Нарезка заданного интервала становится вопросом игры со значениями asOfIndex и amount.

Также, выполняя некоторые копания, нашел способ запросить элемент даты поддокументов внутри массива на основе интервала дат благодаря следующим сообщениям: /questions/26855888/mongodb-elemmatch-neskolko-elementov-v-massive/26855897#26855897 и /questions/5061679/mongodb-subdocument-diapazon-dat-vozvraschaet-nevernyie-rezultatyi/5061689#5061689. Для тех, кто хочет что-то подобное!

function getPostsBetween(recentDate, farthestDate, forLocid) {
    return new Promise(function (posts, none) {
        Post.aggregate(
            {'$match': {'locid': forLocid}},
            {'$unwind' : '$posts'},
            {'$match' :
                {'$and': [
                    {'posts.date': {'$gt': new Date(farthestDate.toISOString())}},
                    {'posts.date': {'$lt': new Date(recentDate.toISOString())}}
                ]
                }
            },
            {"$group" : {
                '_id' : '$_id',
                "posts" : {'$push' : '$posts'}
            }
            })
            .exec()
            .catch(function (err) {
                return none(err);
            })
            .then(function (found) {
                if (found.length === 0 || found.length > 1) return none();
                return found(found[0].posts);
            })
    })
}

0 ответов

Другие вопросы по тегам