首页 > 解决方案 > Mongoose:如何查询嵌套文档并返回字符串结果?

问题描述

进行查询Product.findOne({'variation.sku': req.params.productVariationSKU },{'_id': 0, 'variation.price' :1})以查找产品变体的价格。

但结果返回了所有产品变化的价格。需要帮助找出哪里出错了!

以下是产品架构:

var ProductSchema = new Schema({
    productId: {
        type: Number,
        required: [true, 'Product ID is required'],
        unique: true
    },
    sku: String,
    category: [String],
    language: {
        type: String,
        lowercase: true,
        maxlength: 2,
        required: [true, 'Language code required'],
        index: true,
        unique: true
    },
    name: {
        type: String,
        required: [true, 'Product name is required']
    },
    descLong: String,
    descShort: String,
    mainImageURL: String,
    galleryImageURL: [String],
    variation: [{
        sku: String,
        option: [{
            label: String,
            value: String,
        }],
        inventory: [{
            name: String,
            quantity: Number,
            country: String
        }],
        inStock: Boolean,
        price: mongoose.Types.Decimal128
    }],
    attribute: [{
        label: String,
        value: [String]
    }],
    inStock: Boolean,
    currencySymbol: String,
    slug: String,
    metaTitle: String,
    metaDescription: String,
    relatedAccessory: [Number],
    htmlContentBefore: String,
    htmlContentAfter: String
});

以下是 Postman 的产品对象:

{
    "category": [],
    "galleryImageURL": [
        "TEST.png"
    ],
    "relatedAccessory": [],
    "_id": "5feae4418d686300176dfbbd",
    "productId": 1,
    "language": "en",
    "name": "TEST PRODUCT",
    "descLong": "<p><strong>This is a long description</strong></p>",
    "descShort": "Short Description",
    "mainImageURL": "TEST.png",
    "variation": [
        {
            "option": [
                {
                    "_id": "5feae4418d686300176dfbbf",
                    "label": "Color",
                    "value": "Black"
                }
            ],
            "inventory": [],
            "_id": "5feae4418d686300176dfbbe",
            "sku": "P-1",
            "inStock": true,
            "price": "45"
        },
        {
            "option": [
                {
                    "_id": "5feae4418d686300176dfbc1",
                    "label": "Color",
                    "value": "White"
                }
            ],
            "inventory": [],
            "_id": "5feae4418d686300176dfbc0",
            "sku": "P-2",
            "inStock": true,
            "price": "45"
        }
    ],
    "attribute": [
        {
            "value": [
                "Black",
                "White"
            ],
            "_id": "5feae4418d686300176dfbc2",
            "label": "Color"
        }
    ],
    "currencySymbol": "£",
    "slug": "test",
    "metaTitle": "testmeta",
    "metaDescription": "This is meta description",
    "__v": 0
}

下面是API函数:

app.get('/API/Product/GetProductVariationPrice/:productVariationSKU', async(req, res) => {
  try{
    res.send(await Product.findOne({'variation.sku': req.params.productVariationSKU },{'_id': 0, variation :1}));
  } catch (err) {
    res.status(500).send(err);
  }
});

邮递员返回的结果:

{
    "variation": [
        {
            "price": "45"
        },
        {
            "price": "45"
        }
    ]
}

问题:我怎样才能只获得“45”的变体 SKU“P-1”?作为结果,当前也返回了不想要的变体“P-2”的价格。SKU 应基于传递给 API 的参数。

标签: node.jsexpressmongoose

解决方案


通常,当我们从对象数组中投影特定字段时,它会返回对象数组,

从 MongoDB 4.4 开始,作为使find投影与聚合$project阶段一致的一部分,

  • $reduce迭代数组的循环variation,检查条件是否sku匹配,然后它将返回price
await Product.findOne(
{ "variation.sku": req.params.productVariationSKU },
{
  "_id": 0,
  variation: {
    $reduce: {
      input: "$variation",
      initialValue: 0,
      in: {
        $cond: [
          { $eq: ["$$this.sku", req.params.productVariationSKU] },
          "$$this.price",
          "$$value"
        ]
      }
    }
  }
})

操场


MongoDB 4.4 或以下版本尝试aggregate()

let p = Product.aggregate();
p.match({ "variation.sku": req.params.productVariationSKU });
p.project({
    _id: 0,
    variation: {
        $reduce: {
            input: "$variation",
            initialValue: 0,
            in: {
                $cond: [
                    { $eq: ["$$this.sku", req.params.productVariationSKU] },
                    "$$this.price",
                    "$$value"
                ]
            }
        }
    }
});
res.send(await p.exec());

操场


推荐阅读