繁体   English   中英

在父文档数组猫鼬中填充子文档

[英]Populate subdocument in parent document Array Mongoose

我是JavaScript和Mongoose的新手。 我正在使用express,mongoose和node.js构建一个小项目。 我有一个猫鼬模型-具有交易数组的客户端

    var Client = mongoose.model('Client', {
 name: {
   type: String,
   required: true,
   minlength: 1
 },
 email: {
   type: String
 },
 phone: {
   type: Number
 },
 createdAt: {
   type: Number,
   default: null
 },
 transactions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Transaction' }],
 _creator: {
   type: mongoose.Schema.Types.ObjectId,
   required: true
 }
});

module.exports = {Client};

这是交易模型:

var Client = require('./client');

var Transaction = mongoose.model('Transaction',{
  _creator : { type: mongoose.Schema.Types.ObjectId, ref: 'Client' },
  amount : {type: Number, min: 0},
  date : {type: Number,default: null},
  total: {type: Number,default: null}
});

module.exports = {Transaction};

当我发布新交易时,它将通过并保存在db中:

 app.post('/clients/:id/transactions', authenticate, (req, res) => {
  var id = req.params.id;
  var transaction = new Transaction({
    amount: req.body.amount,
    date: new Date().getTime(),
    total: req.body.total,
    _creator: req.params.id
  })
  if (!ObjectID.isValid(id)) {
  return res.status(404).send();
  }

  transaction.save().then((doc) => {

    Client.findOneAndUpdate({
      _id: id,
      _creator: req.user._id,
      transactions: req.body.transaction
    });

    res.send(doc);
  }, (e) => {
    res.status(400).send(e);
  });

});

我还能够获取与客户关联的所有交易:

  app.get('/clients/:id/transactions', authenticate, (req, res) => {
  var id = req.params.id;
  if (!ObjectID.isValid(id)) {
  return res.status(404).send();
 }
 Transaction.find({
   _creator: id
 }).then((transactions) => {
  res.send({transactions});
 }).catch((e) => {
  res.status(400).send();
 });
});

但是当我对'/ clients'进行GET调用时-事务数组为空:

    {
  "clients": [
    {
      "_id": "1095d6de3867001108b803",
      "name": "Peter",
      "email": "peter@gmail.com",
      "phone": 1232321,
      "_creator": "5321df6d57868ec7001108b801",
      "__v": 0,
      "transactions": [],
      "createdAt": null
    } ]
}

这是对/ clients的GET调用

    app.get('/clients', authenticate,  (req, res) => {
  Client.find({
    _creator: req.user._id,
  })
  .populate('transactions.transaction')
  .then((clients) => {
    res.send({clients});
  }, (e) => {
    res.status(400).send(e);
    console.log('Unable to get clients', e);
  })
});

我知道我可能在做完全错误的事情,但是我不知道该在哪里寻找错误。 请帮忙!

因此,首先我不完全了解Client模型中代表的_creator键,可能是拥有一些客户端的用户标识符,但是如果我错了,请更正我。

老实说,我不知道您为什么要进行双向文档连接(将客户保留在事务中,还将客户保留在事务中)对于mongodb来说,第一种选择更好,使用它可以轻松地通过find找到交易的清单,或者mongodb聚合,但是您无法使用populate获取数据。

在第二个选项中,您需要记住一个文档最大可以有16MB。 而且将成千上万个事务保存在一个阵列中对性能而言也不是很好。 考虑一个示例,您有5000个事务,并且想要显示带有分页的列表(每页50条记录),使用数组选项必须获取整个文档,并将数组拼接为50条记录。 在第一个选项中,您可以使用mongodb跳过和限制。 请考虑一下。

回到问题,您正在做的错误在这里:transaction.save()。then((doc)=> {

Client.findOneAndUpdate({
  _id: id,
  _creator: req.user._id,
  transactions: req.body.transaction
});

res.send(doc);

在这里,您并没有完全说出应如何更新本文档。

使用mongodb findAndModify方法的findOneAndUpdate方法中的猫鼬。 但是参数是从更新开始使用的。 https://docs.mongodb.com/manual/reference/method/db.collection.update/

并且文档还说您喜欢什么参数:Query#findOneAndUpdate([query],[doc],[options],[options.passRawResult],[options.strict],[callback])

因此,第一个query参数是mongo查询,用于在数据库中查找一个文档,第二个参数是具有更新查询的对象,此后,您可以在第三个参数中发送一些其他选项。 因此,您的代码应如下所示:

transaction.save().then((doc) => {

Client.findOneAndUpdate({
  _id: id,
  _creator: req.user._id,
}, {
    $addToSet:  {
        transactions: doc._id,
    }
});

res.send(doc);

您可以使用addToSet或同时push两者都放入数组中,但是addToSet避免在数组中重复。 正如您所了解的,我们将新的交易标识符推入该数组。 毕竟,您只填充transaction密钥。

希望我能帮上忙。 如果您有任何问题,请询问。

在添加事务之前,我将检查客户端是否存在。 交易首先需要客户。

预先警告,我不是一个球迷thencatch所以这个答案不使用它。 我通常在处理多个异步操作时使用async.js。

无论如何,我会这样做

app.post('/clients/:id/transactions', authenticate, (req, res) => {


    Client.findOne({ _id: req.params.id }, (err, client) => {
        if (err)
            return res.status(400).send(err); 
        if (!client)
            return res.status(400).send(new Error('No client'));


        Transaction.create({
            amount: req.body.amount,
            date: new Date(), // I don't think you need .getTime()
            total: req.body.total,
            _creator: client._id
        }, (err, transaction) => {
            if (err)
                return res.status(400).send(err);


            client.transactions.push(transaction._id);
            client.save(err => {
                if (err)
                    return res.status(400).send(err);

                res.json(transaction);
            });
        });
    });


});

最好还打开调试模式以查看查询: mongoose.set('debug', true)

您可能还会发现,对事务模式使用timestamps选项比显式使用date字段更有用

获得客户的交易

app.get('/clients', authenticate,  (req, res) => {
    Client.find({ _creator: req.user._id }).populate('transactions').exec((err, clients) => {
        if (err)
            return res.status(400).send(err);
        res.json(clients);
    });
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM