我有一个Product集合,每个文档都是这样的:
"_id" : ObjectId("574393c59afcfdd3763d91b1"),
"name" : "dummy product name",
"price" : 200,
"category" : ObjectId("574393c59afcfdd3763d91ad"),
"images" : [ ],
"ratings" : [
2
],
"reviews" : [ ],
"purchase_count" : 0,
"tags" : [
ObjectId("574393c59afcfdd3763d91a9"),
ObjectId("574393c59afcfdd3763d91ab")
]
类别和标签是对其各自集合的引用,并且每个都具有名称属性。以下是所有3种模式:
var ProductSchema = new mongoose.Schema({
name : {type: String, required: true},
price : { type: Number,required: true },
tags : [{ type: Schema.Types.ObjectId, ref: 'Tag' }],
purchase_count : {type: Number, default: 0},
reviews : [ReviewSchema],
ratings : [{type: Number, min: 0, max: 10}],
category : {type: Schema.Types.ObjectId, ref: 'ProductCategory'},
images : [{type: String}]
});
var ProductCategorySchema = new mongoose.Schema({
name : { type: String, required: true, unique: true, dropDups: true }});
var TagSchema = new mongoose.Schema({
name : { type: String, required: true, unique: true, dropDups: true, lowercase: true }
});
我正在尝试查询产品集合并返回每个产品的数据,如下所示:
app.models.Product.find({}, function(err, products){
if (err) throw err;
res.json(products);
}).populate('category').populate('tags').exec();
唯一的区别是我想要类别的实际名称而不是代表具有它的ID的集合的文档。我也希望标签相同,我只想要一个代表标签名称的简单字符串数组。我怎样才能在查询中执行此操作?
我尝试通过在第二个populate()之后使用select()并编写'category.name tags.name(然后是所有其他属性)来隐式定义我想要选择的内容但是这不起作用。< / p>
这就是查询的结果:
答案 0 :(得分:1)
这就是我开始工作的方式。感谢Neta Meta为我提供了使用纯JS的想法。
app.models.Product.find({})
.populate('category' , 'name')
.populate('tags', 'name').populate('seller', 'name').exec(function(err, products){
if (err) throw err;
products = products.map(function(a){
var productToSend = {};
productToSend.name = a.name;
productToSend.price = a.price;
productToSend.description = a.description;
if(a.seller != undefined){
productToSend.seller = a.seller.name;
}
if(a.tags != undefined){
productToSend.tags = a.tags.map(function(b){
return b.name;
});
}
productToSend.purchase_count = a.purchase_count;
productToSend.reviews = a.reviews;
productToSend.ratings = a.ratings;
if(a.category != undefined){
productToSend.category = a.category.name;
}
productToSend.images = a.images;
return productToSend;
})
res.json(products);
});
答案 1 :(得分:0)
要选择特定字段
app.models.Product.find({}, function(err, products){
if (err) throw err;
res.json(products);
}).populate('category', 'fieldname1 fieldname2').populate('tags', 'fieldname1 fieldname2').exec();
http://mongoosejs.com/docs/populate.html
但是我在你的架构定义中没有看到任何对任何东西的引用。
此外,如果您有/需要任何关系(这是您似乎需要的),请不要使用mongo。
实际上除非你绝对必须,否则不要使用mongo - 尽量远离mongo。
<强>更新强>
类似的东西。
var res = app.models.Product.find({}, function(err, products){
if (err) throw err;
res.json(products);
}).populate('category', 'fieldname1 fieldname2').populate('tags', 'fieldname1 fieldname2').exec();
res.category = categoty.fieldname;
res.tags = res.tags.map(function(tag){
return tag.fieldname
})
另一种选择可能是 - 添加getter - 不确定这是否可行,因为填充可能发生在...之后...
但是:
ProductSchema.virtual('categoryString').get(function () {
return this.category.fieldname
});
ProductSchema.virtual('tagsArr').get(function () {
return this.tags.map(function(tag){
if(tag && tag.name) {
return tag.fieldname;
}
return '';
});
});
答案 2 :(得分:0)
我不知道为什么在填充查询之前发送响应。在回复之前使用lodash包修改您的产品。
var _ = require('lodash');
app.models.Product.find({}).populate('category tags').exec(function(err, products){
if (err) throw err;
var modified = _.map(products, function (product) {
product.tags = _.map(product.tags, function (tag) { return _.pick(tag, ['name']) });
product.category = _.pick(product.category, ['name']);
return product;
});
res.json(modified);
});