MongoDB / Mongoose搜索并创建特定的子文档

时间:2018-04-05 14:12:27

标签: node.js mongodb mongoose

我正在nodejs / express / mongodb / mongoose中构建REST API。我最近开始使用MongoDB / Mongoose,我仍有一些疑问。

我想要实现的是访问特定的用户包(用户可以拥有多个包),而且我希望能够添加到那个包包参与者/付款人。 (用户包可以有多个参与者/付款人)

我的mongoose用户模式包含其余模式。我为每个人创建了一个模式,因为我相信由于ObjectId会更容易直接找到给定的包或参与者(不确定这是否正确)。

Mongoose Modal / Schemas:

const PayerSchema = new Schema({
  name: {
    type: String
  },
  amount: {
    type: Number
  }
});

const BagSchema = new Schema({
  name: {
    type: String
  },
  type: {
    type: String
  },
  payers: [PayerSchema]
});

const UserSchema = new Schema({
  name: {
    type: String,
    required: [true, 'User name field is required']
  },
  bags: [BagSchema]
});

module.exports = mongoose.model('User', UserSchema);

我能够为新用户创建CRUD控制器方法,但我仍然不确定:

  1. 为特定用户创建一个新包(我能够这样做但不确定它是否正确)
  2. 为特定用户在特定包中创建新参与者。 (addPayer方法错误需要帮助)
  3. 查看我的控制器用户/行李/参与者方法:

    const User = require('../models/userModel');
    
    getAllUserBags: (req, res, next) => {
        User.findById({ _id: req.params.id }).then((user) => {
          res.send(user.bags);
        })
        .catch(next);
      },
      getOneUserBag: (req, res, next) => {
        console.log(req.params.bagid);
        User.find({ 'bags._id': req.params.bagid}, {"bags.$" : 1}).then((obj) => {
          res.send(obj);
        })
        .catch(next);
      },
      createBag: (req, res, next) => {
        let bag = req.body.bag;
        User.findOneAndUpdate(
          {_id: req.body.id},
          {$push: {bags: bag}
        }).then(() => {
          //Unnecessary - just to return update user with new bag.
          User.findOne({_id: req.body.id}).then((user) => {
            res.send(user);
          })
        }).catch(next);
      },
      addPayer: (req, res, next) => {
        let payer = req.body.payer;
        User.find(
          {'bags._id': req.params.bagid},
          {"bags.$" : 1},
          {$push: {payers: payer}
        }).then((obj) => {
          console.log(obj);
          //Unnecessary - just to return update user with new bag.
          // User.findOne({_id: req.body.id}).then((user) => {
          //   res.send(user);
          // })
        }).catch(next);
      } 
    

    感谢您的帮助

1 个答案:

答案 0 :(得分:1)

根据我们讨论的内容,只要确保一个User文档不超过MongoDB文档的16MB限制,您的User架构就足以满足您的要求。

  

为特定用户创建一个新包(我能够这样做,但不确定它是否正确)

你很好。但是,有一些改进:

createBag: (req, res, next) => {
  User.findByIdAndUpdate(req.body.id, {
      $push: { bags: req.body.bag }
    }, {
      new: true // this will make the query getting the updated document
    })
    .then(user => {
      res.json(user);
    })
    .catch(next);
})
  

为特定用户在特定行李中创建新参与者。 (addPayer方法错误需要帮助)

由于您决定嵌套'行李,bag.id可能会在User个文档中重复。请参阅this以了解可能性。因此,我建议您使用userIdbagId

getOneUserBag: (req, res, next) => {
  User.findOne({
      _id: req.params.userId,
      bags._id: req.params.bagId
    })
    .then(user => {
      if (!user) res.status(404).end();

      let bag = user.bags.id(req.params.bagId);

      res.json(bag);
    })
    .catch(next);
}

addPayer: (req, res, next) => {
  User.findOneAndUpdate({
      _id: req.params.userId,
      bags: $elemMatch: {
        _id: req.params.bagId
      }
    }, {
      $push: { 'bags.$.payers': req.body.payer } // Use 'positional $' operator along with $elemMatch in the query to update only the matched bag
    }, {
      new: true // Do not forget the 'new' options to get the updated document
    })
    .then(user => {
      if (!user) res.status(404).end();

      res.json(user);
    })
    .catch(next);
}

并在路由器中

router.get('/users/:userId/bags/:bagId', getOneUserBag);
router.post('/users/:userId/bags/:bagId/payers', addPayer);

getAllUserBags()中,您对User.findById()使用了错误的语法:

getAllUserBags: (req, res, next) => {
  User.findById(req.params.id) // Not { _id: req.params.id }
    .then((user) => {
      res.json(user.bags);
    })
    .catch(next);
}