猫鼬骨料
Mongoose aggregate
我在 Mongo、Mongoose 和 Node.js 方面需要一些帮助。
在下面的代码中,我想加入 carrinho
和 produtos
集合以检索 produtos
_id
、price
和 description
在同一个 array/object.
我的Carrinho
架构
const Carrinho = new mongoose.Schema(
{
title: {
type: String,
},
produtos: [{
price: Number,
produto: { type: mongoose.Schema.Types.ObjectId, ref:
"Produtos" }
}
],
total: {
type: Number,
},
},
{
timestamps: true
})
我的Produtos
架构
const Produtos = new mongoose.Schema(
{
description: {
type: String,
required: true,
},
gtin: {
type: String,
required: true,
unique: true,
},
thumbnail: {
type: String,
},
price: {
type: Number,
}
},
{
timestamps: true
}
)
阅读 aggregate
文档后,这是我得到的最好的文档:
Carrinho.aggregate([
{ "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } },
{
"$lookup": {
"from": "produtos",
"localField": "produtos._id",
"foreignField": "_id",
"as": "produtosnocarrinho"
}
},
{
"$addFields": {
"total": {
"$reduce": {
"input": "$produtos",
"initialValue": 0,
"in": { "$add": ["$$value", "$$this.price"] }
}
}
}
}
]).exec((err, data) => {
if (err) res.json(err)
res.json(data)
});
这是结果:
[
{
"_id": "5cb76d7d99c3f4062f512537",
"title": "Carrinho do Lucas",
"produtos": [
{
"_id": "5cafead2bc648978100d7698",
"price": 20.1
},
{
"_id": "5cae911adf75ac4d3ca4bcb6",
"price": 20.1
},
{
"_id": "5cb0f0adc5fb29105d271499",
"price": 20.1
}
],
"createdAt": "2019-04-17T18:16:29.833Z",
"updatedAt": "2019-04-19T00:50:43.316Z",
"__v": 3,
"produtosnocarrinho": [
{
"_id": "5cae911adf75ac4d3ca4bcb6",
"description": "AÇÚCAR REFINADO UNIÃO 1KGS",
"gtin": "7891910000197",
"thumbnail": "7891910000197",
"createdAt": "2019-04-11T00:58:02.296Z",
"updatedAt": "2019-04-11T00:58:02.296Z",
"__v": 0
},
{
"_id": "5cafead2bc648978100d7698",
"description": "HASBRO MR. POTATO HEAD MALETA DE PEÇAS",
"gtin": "5010994598815",
"thumbnail": "pecas_300x300-PU3435f_1.jpg",
"createdAt": "2019-04-12T01:33:06.628Z",
"updatedAt": "2019-04-12T01:33:06.628Z",
"__v": 0
},
{
"_id": "5cb0f0adc5fb29105d271499",
"description": "REPELENTE EXPOSIS INFANTIL SPRAY",
"gtin": "7898392800055",
"thumbnail": "PU28bb9_1.jpg",
"createdAt": "2019-04-12T20:10:21.363Z",
"updatedAt": "2019-04-12T20:10:21.363Z",
"__v": 0
}
],
"total": 60.300000000000004
}
]
以下查询会有帮助:
models.Carrinho.aggregate(
[
{ "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } },
{
"$lookup": {
"from": "produtos",
"localField": "produtos._id",
"foreignField": "_id",
"as": "produtosnocarrinho"
}
},
{
"$addFields": {
"total": {
"$reduce": {
"input": "$produtos",
"initialValue": 0,
"in": { "$add": ["$$value", "$$this.price"] }
}
}
}
},
{$unwind : '$produtos'},
{$unwind : '$produtosnocarrinho'},
{$redact: { $cond: [{
$eq: [
"$produtos._id",
"$produtosnocarrinho._id"
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
{ $project: {
_id : 1,
title : 1,
produtosData : {
_id : "$produtos._id",
price : "$produtos.price",
description : "$produtosnocarrinho.description"
},
total : 1,
createdAt: 1,
updatedAt : 1
}
},
{
$group : {
_id : {
_id : '$_id',
title : '$title',
total : '$total',
createdAt : '$createdAt',
updatedAt : '$updatedAt'
},
produtosData: {$push: "$produtosData" }
}
},
{ $project: {
_id : '$_id._id',
title : '$_id.title',
total : '$_id.total',
createdAt : '$_id.createdAt',
updatedAt : '$_id.updatedAt',
produtosData: '$produtosData'
}
}
]).exec((err, data) => {
if (err) res.json(err)
res.json(data)
});
Output :
[{
"_id": "5cbc42c24502a7318952d7b2",
"title": "Carrinho do Lucas",
"total": 60.300000000000004,
"createdAt": "2019-04-21T10:15:30.629Z",
"updatedAt": "2019-04-21T10:15:30.629Z",
"produtosData": [{
"_id": "5cafead2bc648978100d7698",
"price": 20.1,
"description": "HASBRO MR. POTATO HEAD MALETA DE PEÇAS"
}, {
"_id": "5cae911adf75ac4d3ca4bcb6",
"price": 20.1,
"description": "AÇÚCAR REFINADO UNIÃO 1KGS"
}, {
"_id": "5cb0f0adc5fb29105d271499",
"price": 20.1,
"description": "REPELENTE EXPOSIS INFANTIL SPRAY"
}]
}]
性能取决于来自查找查询的产品匹配数据因为我们正在做双重展开。
我在 Mongo、Mongoose 和 Node.js 方面需要一些帮助。
在下面的代码中,我想加入 carrinho
和 produtos
集合以检索 produtos
_id
、price
和 description
在同一个 array/object.
我的Carrinho
架构
const Carrinho = new mongoose.Schema(
{
title: {
type: String,
},
produtos: [{
price: Number,
produto: { type: mongoose.Schema.Types.ObjectId, ref:
"Produtos" }
}
],
total: {
type: Number,
},
},
{
timestamps: true
})
我的Produtos
架构
const Produtos = new mongoose.Schema(
{
description: {
type: String,
required: true,
},
gtin: {
type: String,
required: true,
unique: true,
},
thumbnail: {
type: String,
},
price: {
type: Number,
}
},
{
timestamps: true
}
)
阅读 aggregate
文档后,这是我得到的最好的文档:
Carrinho.aggregate([
{ "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } },
{
"$lookup": {
"from": "produtos",
"localField": "produtos._id",
"foreignField": "_id",
"as": "produtosnocarrinho"
}
},
{
"$addFields": {
"total": {
"$reduce": {
"input": "$produtos",
"initialValue": 0,
"in": { "$add": ["$$value", "$$this.price"] }
}
}
}
}
]).exec((err, data) => {
if (err) res.json(err)
res.json(data)
});
这是结果:
[
{
"_id": "5cb76d7d99c3f4062f512537",
"title": "Carrinho do Lucas",
"produtos": [
{
"_id": "5cafead2bc648978100d7698",
"price": 20.1
},
{
"_id": "5cae911adf75ac4d3ca4bcb6",
"price": 20.1
},
{
"_id": "5cb0f0adc5fb29105d271499",
"price": 20.1
}
],
"createdAt": "2019-04-17T18:16:29.833Z",
"updatedAt": "2019-04-19T00:50:43.316Z",
"__v": 3,
"produtosnocarrinho": [
{
"_id": "5cae911adf75ac4d3ca4bcb6",
"description": "AÇÚCAR REFINADO UNIÃO 1KGS",
"gtin": "7891910000197",
"thumbnail": "7891910000197",
"createdAt": "2019-04-11T00:58:02.296Z",
"updatedAt": "2019-04-11T00:58:02.296Z",
"__v": 0
},
{
"_id": "5cafead2bc648978100d7698",
"description": "HASBRO MR. POTATO HEAD MALETA DE PEÇAS",
"gtin": "5010994598815",
"thumbnail": "pecas_300x300-PU3435f_1.jpg",
"createdAt": "2019-04-12T01:33:06.628Z",
"updatedAt": "2019-04-12T01:33:06.628Z",
"__v": 0
},
{
"_id": "5cb0f0adc5fb29105d271499",
"description": "REPELENTE EXPOSIS INFANTIL SPRAY",
"gtin": "7898392800055",
"thumbnail": "PU28bb9_1.jpg",
"createdAt": "2019-04-12T20:10:21.363Z",
"updatedAt": "2019-04-12T20:10:21.363Z",
"__v": 0
}
],
"total": 60.300000000000004
}
]
以下查询会有帮助:
models.Carrinho.aggregate(
[
{ "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } },
{
"$lookup": {
"from": "produtos",
"localField": "produtos._id",
"foreignField": "_id",
"as": "produtosnocarrinho"
}
},
{
"$addFields": {
"total": {
"$reduce": {
"input": "$produtos",
"initialValue": 0,
"in": { "$add": ["$$value", "$$this.price"] }
}
}
}
},
{$unwind : '$produtos'},
{$unwind : '$produtosnocarrinho'},
{$redact: { $cond: [{
$eq: [
"$produtos._id",
"$produtosnocarrinho._id"
]
},
"$$KEEP",
"$$PRUNE"
]
}
},
{ $project: {
_id : 1,
title : 1,
produtosData : {
_id : "$produtos._id",
price : "$produtos.price",
description : "$produtosnocarrinho.description"
},
total : 1,
createdAt: 1,
updatedAt : 1
}
},
{
$group : {
_id : {
_id : '$_id',
title : '$title',
total : '$total',
createdAt : '$createdAt',
updatedAt : '$updatedAt'
},
produtosData: {$push: "$produtosData" }
}
},
{ $project: {
_id : '$_id._id',
title : '$_id.title',
total : '$_id.total',
createdAt : '$_id.createdAt',
updatedAt : '$_id.updatedAt',
produtosData: '$produtosData'
}
}
]).exec((err, data) => {
if (err) res.json(err)
res.json(data)
});
Output :
[{
"_id": "5cbc42c24502a7318952d7b2",
"title": "Carrinho do Lucas",
"total": 60.300000000000004,
"createdAt": "2019-04-21T10:15:30.629Z",
"updatedAt": "2019-04-21T10:15:30.629Z",
"produtosData": [{
"_id": "5cafead2bc648978100d7698",
"price": 20.1,
"description": "HASBRO MR. POTATO HEAD MALETA DE PEÇAS"
}, {
"_id": "5cae911adf75ac4d3ca4bcb6",
"price": 20.1,
"description": "AÇÚCAR REFINADO UNIÃO 1KGS"
}, {
"_id": "5cb0f0adc5fb29105d271499",
"price": 20.1,
"description": "REPELENTE EXPOSIS INFANTIL SPRAY"
}]
}]
性能取决于来自查找查询的产品匹配数据因为我们正在做双重展开。