我如何查询嵌套的文档并从中返回属性?

我有一个产品集合,每个文档看起来像这样:

"_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集合。 我也想为标签一样,我只想要一个简单的string数组来表示标签名称。 我怎么能在查询中做到这一点?

我尝试通过在第二个populate()之后使用select()并编写'category.name tags.name(然后所有其他属性)'隐式定义我想要select的内容,但是这不起作用。

这是查询的结果如下所示:

在这里输入图像描述

要select特定的领域,你会

 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 }) 

另一个select可能是 – 添加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 ''; }); }); 

这是我得到它的工作。 信用去Neta元给我使用纯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); }); 

我不知道为什么你在填充查询之前发送响应。 在回应之前使用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); });