在Mongoose中,我应该返回一个数组还是逐个返回数据?

4
我有一个使用IOS创建的简单应用程序,它是一个问卷应用程序。每当用户点击“播放”时,它将调用一个请求到node.js/express服务器。

enter image description here

enter image description here

技术上,用户点击答案后,它将转到下一个问题。

enter image description here

我不确定该使用哪种方法来获取问题/题目

  1. 一次性获取所有数据并呈现给用户 - 这是一个数组
  2. 随着用户进展到下一个问题,逐个获取数据 - 每次调用一个数据

API示例

// Fetch all the data at once
app.get(‘/api/questions’, (req, res, next) => {
  Question.find({}, (err, questions) => {
    res.json(questions);
  });
});

// Fetch the data one by one
app.get('/api/questions/:id', (req, res, next) => {
  Question.findOne({ _id: req.params.id }, (err, question) => {
   res.json(question);
  });
});

第一种方法的问题在于,假设有200个问题,mongodb一次获取所有问题可能会很慢,并且网络请求也可能很慢。

第二种方法的问题是,我无法想象如何实现这一点,因为每个问题都是独立的,触发下一个api调用就很奇怪,除非在问题mongodb中有一个计数器或级别。

仅为了清晰起见,这是Mongoose中的问题数据库设计。

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

const QuestionSchema = new Schema({
    question: String,
    choice_1: String,
    choice_2: String,
    choice_3: String,
    choice_4: String,
    answer: String
});
4个回答

1
非常好的问题。我猜这个问题的答案取决于你对这个应用的未来计划。
如果你计划有500个问题,那么一个一个地获取它们将需要500个API调用,这并不总是最好的选择。另一方面,如果你一次获取所有问题,这将延迟响应,具体取决于每个对象的大小。
因此,我的建议是使用分页。带来10个结果,当用户到达第8个问题时,更新列表以显示下一个10个问题。
这是移动开发人员的常见做法,这也会为你提供灵活性,根据用户先前的响应更新下一个问题。例如自适应测试等。
编辑
你可以在你的请求中添加pageNumber和pageSize查询参数,以从服务器获取问题,类似于这样。
myquestionbank.com/api/questions?pageNumber=10&pageSize=2

在服务器上接收这些参数。
var pageOptions = {
    pageNumber: req.query.pageNumber || 0,
    pageSize: req.query.pageSize || 10
}

在从数据库查询时,提供这些额外的参数。

Question.find()
    .skip(pageOptions.pageNumber * pageOptions.pageSize)
    .limit(pageOptions.pageOptions)
    .exec(function (err, questions) {
        if(err) {
        res.status(500).json(err); return; 
        };

        res.status(200).json(questions);
    })

注意:请从零(0)开始设置您的pageNumber,这不是强制要求,但这是惯例。 skip()方法允许您跳过前n个结果。考虑第一个情况,pageNumber将为零,因此产品(pageOptions.pageNumber * pageOptions.pageSize)将变为零,并且不会跳过任何记录。但对于下一次(pageNumber=1),该乘积将导致10。因此,它将跳过已经处理过的前10个结果。 limit()该方法限制了结果中提供的记录数量。
请记住,您需要在每个请求中更新pageNumber变量。(尽管您也可以变更limit,但建议在所有请求中保持相同)
因此,您所要做的就是,当用户到达倒数第二个问题时,您可以向服务器请求10(页面大小)个问题,并将其放入数组中。
代码参考:here

哈哈...我在node.js方面不是很擅长,但我会尽力提供帮助。 :) - Dave Ranjan
@airsoftFreak:我猜这应该会对你有所帮助 :) - Dave Ranjan
@DaveRanjan 如果你不是同时获取所有问题,那么通过500个不同的API调用获取500个问题并不是一个问题。 - Vince Bowdren

1
我会用Dave的方法,但是在这里我会更详细地介绍一下。在您的应用程序中,创建一个将包含问题的数组。然后还要存储一个值,表示用户当前所在的问题,例如称之为index。然后你有以下伪代码:
index = 0
questions = []

现在你已经有了这个,当用户启动应用程序时,加载10个问题(参见Dave的答案,使用MongoDB的skip和limit),然后将它们添加到数组中。向用户提供questions[index]。一旦索引达到8(第9个问题),通过API加载10个更多的问题,并将它们添加到数组中。这样,您将始终为用户提供可用的问题。

我有点喜欢Dave的方法,但如果可能的话,你能提供完整的代码吗?这样我就可以接受你的答案了。 - airsoftFreak
戴夫已经更新了他的帖子,我想那应该会有所帮助。 - NikxDa

0

你可以在MongoDB中使用限制和跳过的概念。

当你第一次调用API时,你可以设置limit=20和skip=0,每次再次调用API时增加skip计数。

第一次=> limit =20,skip=0

当你点击下一页 => limit=20,skip=20,以此类推。

app.get(‘/api/questions’, (req, res, next) => {
  Question.find({},{},{limit:20,skip:0}, (err, questions) => {
    res.json(questions);
  });
});

它会重复相同的数据吗?比如说,如果我点击下一页,然后它又显示了相同的文档? - airsoftFreak
第一次限制=20,跳过=0。当您单击下一个时,限制=20,但是这次跳过=20,因为您想查看接下来的20个结果,以此类推。 - Shumi Gupta

0

你说得对,我也认为第一种选项是一个绝不使用的选项。如果数据没有被使用或者在上下文中有可能不被使用,那么获取这么多数据是没有意义的。

你可以做的是暴露一个新的API调用:

app.get(‘/api/questions/getOneRandom’, (req, res, next) => {
    Question.count({}, function( err, count){
        console.log( "Number of questions:", count );
        var random = Math.ceil(Math.random() * count);
        // random now contains a simple var
        now you can do
        Question.find({},{},{limit:1,skip:random}, (err, questions) => {
            res.json(questions);
        });
    })

});

skip:random 确保每次都获取一个随机问题。这只是从所有问题中获取随机问题的基本思路。您可以添加更多逻辑,以确保用户不会获得在前面步骤中已经解决过的任何问题。

希望这有所帮助 :)


2
那么从技术上讲,这个解决方案只是从问题集合中获取一个随机文档? - airsoftFreak
1
这可能会导致同样的问题出现两次。 - NikxDa
@NikxDa 我已经在我的评论中提到了:“你可以添加进一步的逻辑,以确保用户不会得到他在之前步骤中已经解决过的任何问题” :)airsoftFreak. 是的。由于您没有不同类别的问题,并且希望应用程序具有灵活性(即不向每个用户或同一用户在从头开始时显示完全相同的问题序列),如果您想知道如何保持不显示用户已经解决的问题的可能性,请让我知道 :) 谢谢。 - Muhammad Ahsan Ayaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接