[英]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
密钥。
希望我能帮上忙。 如果您有任何问题,请询问。
在添加事务之前,我将检查客户端是否存在。 交易首先需要客户。
预先警告,我不是一个球迷then
和catch
所以这个答案不使用它。 我通常在处理多个异步操作时使用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.