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

时间:2016-05-24 00:56:15

标签: javascript node.js mongodb mongoose

我有一个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>

这就是查询的结果:

enter image description here

3 个答案:

答案 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);
});