Nodejs mongoose或mongodb支持对sub-document进行分页获取数据吗?

Nodejs mongoose或mongodb支持对sub-document进行分页获取数据吗?

示例document的数据结构及示例数据如下: <code>

var ReplyMessagesSchema=new Schema({ rcode:String, rname:String });

var TMessagesSchema=new Schema({ parentmsg:String, replymsg:[ReplyMessageSchema] });

mongoose.model(‘TMessages’,TMessagesSchema); mongoose.model(‘ReplyMessages’,ReplyMessagesSchema);

示例数据:

{ "_id" : ObjectId(“52e23036b7ceecc00f8158f6”), “parentmsg” : “父类的字段”, “replymsg” : [{ "_id" : ObjectId(“52e5c81067861810067a6e98”), “rcode” : “子类代码1”, “rname” : “子类名字1”, }, { "_id" : ObjectId(“52e5c85167861810067a6e99”), “rcode” : “子类代码2”, “rname” : “子类名字2”, }, { "_id" : ObjectId(“52e5cb060e0dad981eedc74d”), “rcode” : “子类代码3”, “rname” : “子类名字3”, }, { "_id" : ObjectId(“52e5cd590e0dad981eedc74e”), “rcode” : “子类代码4”, “rname” : “子类名字4”, }, { "_id" : ObjectId(“52e5cd590e0dad981eedc74f”), “rcode” : “子类代码5”, “rname” : “子类名字5”, }, { "_id" : ObjectId(“52e5cf406fdb99d8159455f3”), “rcode” : “子类代码6”, “rname” : “子类名字6”, }], } </code>

下面的调用的方法会把所有的replymsg都取出来,我现在只想取部分的replymsg数据,想实现分页取数据的效果,请问如果实现? exports.getmessages = function (messageid, page, callback) { var query={_id:messageid}; // var options = { skip: (page - 1) * 3, limit: 3}; // TMessages.findOne(query, {}, options, callback);

TMessages.findOne(query, {}, {}, callback); };

</code>


3 回复

当然可以实现对嵌套文档(sub-document)的分页获取。下面将展示如何使用Mongoose实现这一功能。

示例代码

首先,我们需要定义模型:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

var ReplyMessageSchema = new Schema({
    rcode: String,
    rname: String
});

var TMessageSchema = new Schema({
    parentmsg: String,
    replymsg: [ReplyMessageSchema]
});

const TMessage = mongoose.model('TMessage', TMessageSchema);

接下来,我们编写一个函数来实现分页获取子文档的功能:

exports.getmessages = function (messageId, page, limit, callback) {
    const query = {_id: messageId};
    const options = {
        fields: {}, // 可以在这里指定需要返回的字段
        lean: true, // 将Mongoose对象转换为纯JavaScript对象
        skip: (page - 1) * limit,
        limit: limit
    };

    TMessage.findOne(query, 'replymsg', options)
        .then(result => {
            if (!result) {
                return callback(new Error('No document found'));
            }
            callback(null, result.replymsg);
        })
        .catch(err => {
            callback(err);
        });
};

解释

  1. 定义模型:我们首先定义了两个模式 ReplyMessageSchemaTMessageSchema
  2. 查询函数getmessages 函数接收三个参数:messageIdpagelimit。其中 messageId 是父文档的 _idpagelimit 分别用于分页。
  3. 选项设置:在 options 对象中,我们设置了 skiplimit 来实现分页逻辑。skip 计算当前页应该跳过的文档数量,而 limit 则指定了每页显示的文档数量。
  4. 查询执行:我们使用 findOne 方法查询父文档,并通过 fields 参数指定只返回 replymsg 字段。然后通过 lean 方法将结果转换为普通的 JavaScript 对象,这样可以提高性能并简化结果处理。
  5. 错误处理:如果找不到对应的文档,则返回一个错误。否则,调用回调函数并将子文档数组作为结果返回。

通过这种方式,你可以轻松地实现对嵌套文档的分页获取功能。


我查了一些资料,说可以用map-reduce来解决,但感觉map-reduce用在生产环境效率不高,最后就通过全部取出来再用js的数组函数来操作算了。这样虽然服务器占了点内存,但网络传输数据量就小点。 <code> exports.getmessage = function (messageid, page, callback) { // var query={_id:messageid}; // var options = { skip: (page - 1) * config.pagesize, limit: config.pagesize}; // TMessages.findOne(query, {}, options, callback);

var query={_id:messageid};

// var options = { skip: (page - 1) * config.pagesize, limit: config.pagesize}; TMessages.findOne(query, {}, {}, function(err,data){ if(err){ console.log(‘getmessage err:’+err); } var begin=(page-1)config.pagesize; var end=pageconfig.pagesize; var replymsg=data.replymsg.slice(begin,end); data.replymsg=replymsg; callback(err,data); }); }; </code>

在Node.js中使用Mongoose或MongoDB对嵌套文档(sub-document)进行分页获取数据是可行的。下面提供一个具体的示例来展示如何实现这一点。

示例代码

首先,我们需要修改getmessages函数以包含分页选项:

const mongoose = require('mongoose');
const TMessages = mongoose.model('TMessages');

exports.getmessages = function (messageid, page, pageSize, callback) {
    const query = {_id: messageid};
    const options = {
        fields: {}, // 可以在这里指定需要返回的字段
        lean: true, // 返回纯对象而不是Mongoose文档
        page: page, // 当前页码
        limit: pageSize // 每页显示的条目数量
    };

    TMessages.findOne(query)
        .select('replymsg') // 仅选择replymsg字段
        .exec(function (err, tmessage) {
            if (err) return callback(err);
            if (!tmessage) return callback(null, []);

            // 对replymsg数组进行分页处理
            const start = (page - 1) * pageSize;
            const end = start + pageSize;
            const paginatedReplymsgs = tmessage.replymsg.slice(start, end);

            callback(null, paginatedReplymsgs);
        });
};

解释

  1. 查询条件query对象定义了根据messageid查找特定文档的条件。
  2. 分页选项options对象包含分页参数,如当前页码(page)和每页条目数(limit)。
  3. 字段选择:通过.select('replymsg')方法,我们只选择replymsg字段,从而减少返回的数据量。
  4. 分页处理:在找到对应的文档后,我们通过切片操作(slice)对replymsg数组进行分页处理,提取出当前页的数据。

这样,您就可以实现对嵌套文档的分页获取功能了。

回到顶部