【问题标题】:Mongodb: select all the fields in the document with few fields' value set conditionallyMongodb:有条件地选择文档中所有字段的值设置很少的字段
【发布时间】:2021-09-27 03:06:18
【问题描述】:

我们有一个名为product 的集合,它存储具有不同定义属性的不同类型的产品(例如电子产品、食品、鞋类等)。用例是,我们希望选择响应特定产品返回的所有字段,而不在selectfindprojectaggregate 中定义它们。这样做的原因是,产品的类型完全不同,我们不知道要选择哪些字段。例如 - 电子产品的尺寸以英寸为单位,而食品则具有制造日期和有效期。我们想要的是,选择文档中存在的所有字段,并在某些通用字段上具有某些条件,例如 - tax、gtin 等。

问题是,使用 find 我只能选择或取消选择字段而不添加任何条件,而使用聚合我将不得不提及响应中需要的项目中的每个字段,并且我事先不知道字段名称。

这是适用于每个产品的通用产品架构:

const mongoose = require('mongoose');
const schema = mongoose.Schema({
  name: { type: String, required: [true, 'Product name is required.'] },
  product_type: String,
  description: String,
  company: String,
  gtin: String,
  tax: Number,
  price: Number
}, {strict: false});

对于这两个产品文档:

[{
    "name": "Coca-Cola Soft Drink, 2L PET Bottle",
    "product_type": "Beverages",
    "description": "The original cola flavoured refreshment to be enjoyed with loved ones",
    "company": "Coca-Cola",
    "gtin": "74125896352SDSFEED343", 
    "price": 83,
    "package_weight": "2.14 Kg"
},
{
    "name": "Lenovo X1 Titanium Yoga (Intel)",
    "product_type": "Electronics",
    "description": "Lenovo X1 Titanium Yoga (Intel)",
    "company": "Lenovo",
    "price": 50000,
    "tax": 5,
    "screen_size": "14 inches",
    "operating_system": "Windows 10 Pro"
}]

预期输出是:

[{
    "name": "Coca-Cola Soft Drink, 2L PET Bottle",
    "product_type": "Beverages",
    "description": "The original cola flavoured refreshment to be enjoyed with loved ones",
    "company": "Coca-Cola",
    "gtin": "74125896352SDSFEED343", 
    "price": 83,
    "tax": 0,
    "package_weight": "2.14 Kg"
},
{
    "name": "Lenovo X1 Titanium Yoga (Intel)",
    "product_type": "Electronics",
    "description": "Lenovo X1 Titanium Yoga (Intel)",
    "company": "Lenovo",
    "gtin": null,
    "price": 50000,
    "tax": 5,
    "screen_size": "14 inches",
    "operating_system": "Windows 10 Pro"
}]

即如果没有为产品定义 tax 或 gtin,则响应必须返回 tax 为 0 且 gtin 为 null 以及文档中存在的所有字段。

【问题讨论】:

  • 您是否尝试过使用$set$addFields 进行聚合?
  • @Joe 不,我没有。我现在试一试。谢谢你的建议。
  • @Joe 当我将它用于获取特定产品或所有产品时,这解决了我的问题。但是,对于搜索聚合,它不是。我在响应中也需要 searchScore。当不存在但不存在 searchScore 时,它​​返回 gtin null 和 tax 0 的结果,因为在这种情况下我已经删除了项目。
  • 这是我的聚合搜索查询:{ $search: { text: { query: search_string, path: search_path, fuzzy: { maxEdits: 2} } } }, { $set: { "gtin": {$ifNull: ["$gtin", null]}, "domain": { $ifNull: ["$domain", null] }, "tax": { $ifNull: ["$tax", 0] } } } ]; 如果我在这里使用 project 来获取 searchScore,我将不得不提及字段名称,如果我不使用 project 将不会得到 searchScore结果。
  • 你确定不能在 $set 中获取 searchScore 吗?

标签: mongodb mongoose aggregate


【解决方案1】:

所以,根据@Joe 的建议,我已经解决了我的所有三个用例。在这里,我发布了为获取所需结果而形成的查询(即,如果任何文档中都不存在这些字段以及文档中存在的不同字段,则使用默认值将一些通用字段添加到产品文档中)。

1.获取所有文档

[{ 
    $set: {  
        "gtin": {$ifNull: ["$gtin", null]},
        "domain":  { $ifNull: ["$domain", null] },
        "tax": { $ifNull: ["$tax", 0] } 
    } 
}];

2。通过匹配条件获取特定文档

[{
    "$match":{"_id":"60f668ccadb9e9147ed8a8ec"}
 },
 { 
     $set: {  
        "gtin": {$ifNull: ["$gtin", null]},
        "domain":  { $ifNull: ["$domain", null] },
        "tax": { $ifNull: ["$tax", 0] } 
     } 
 }];

3.应用搜索并获取所需结果

[   
    { 
        $search: { 
            text: { 
               query: <STRING_TO_SEARCH>,
               path: <PATH_TO_LOOK_IN>, 
               fuzzy: { maxEdits: 2} 
            } 
        } 
    },
    { 
        $set: {
            "gtin": {$ifNull: ["$gtin", null]},
            "domain":  { $ifNull: ["$domain", null] }, 
            "tax": { $ifNull: ["$tax", 0] }, 
             score: { $meta: "searchScore" } 
        } 
    }
];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 2017-03-06
    • 1970-01-01
    • 2014-10-24
    • 1970-01-01
    • 2022-12-04
    相关资源
    最近更新 更多