填充父文档Array Mongoose中的子文档

时间:2017-07-06 18:32:48

标签: javascript node.js mongodb express 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);
  })
});

我知道我可能做错了但我不知道在哪里需要找错。请帮忙!

2 个答案:

答案 0 :(得分:1)

所以首先我不知道客户端模型代表什么_creator键,它可能是有一些客户的用户标识符,但如果我错了请纠正我。

老实说,我不知道你为什么要进行双向文档连接,(保持客户端在事务中,并在客户端保持事务)在我看来第一个选项对于mongodb更好,并且使用它可以轻松获得事务列表查找或mongodb聚合,但您无法使用populate获取数据。

在第二个选项中,您需要记住一个文档最多可以有16MB。并且在一个阵列中保留数千个事务并不能很好地提高性能。考虑一下你有5000个事务的例子,你想要显示带分页的列表(每页50个记录),使用数组选项你必须获得整个文档,并将数组拼接到50个记录。在第一个选项中,您可以使用mongodb skip和limit。请考虑一下。

回答问题,你在做的错误就在这里:     transaction.save()。then((doc)=> {

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

res.send(doc);

这里您没有确切说明本文档应如何更新。

使用mongodb findAndModify方法在方法findOneAndUpdate中进行Mongoose。但params用于更新。 https://docs.mongodb.com/manual/reference/method/db.collection.update/

还有文档说你有什么类似的: 查询#findOneAndUpdate([query],[doc],[options],[options.passRawResult],[options.strict],[callback])

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

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

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

res.send(doc);

您可以使用addToSetpush将元素放入数组,但addToSet避免重复数组。然后,我们将新的事务标识符推送到此数组中。毕竟你只填充transaction键。

我希望我帮助过。如果您有任何疑问,请询问。

答案 1 :(得分:1)

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

预先警告,我不是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 option对事务架构比明确使用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);
    });
});