【问题标题】:Compare integers stored as Strings in Mongodb比较在 Mongodb 中存储为字符串的整数
【发布时间】:2020-05-19 14:44:47
【问题描述】:

在下面的集合中,“数量”列包含整数值,但数据类型是字符串。

我想将“数量”字段与聚合中的整数进行比较,将“仓库”字段与字符串“A”进行比较。 ("数量" > 2 和 "仓库" = "A")

[无法将集合中的数据类型更改为整数,因为存在巨大的依赖关系]

编辑需要检索所有列和所有符合条件的文档。

查询得到不正确的结果

db.runCommand(
    {
        aggregate: "products", pipeline: [
            {
                $match: {
                    instock: {
                        $elemMatch: {
                            warehouse: "A",
                            qty: { $gt: "2" }
                        }
                    }
                }
            },
            { $project: { _id: 0 } }],
        cursor: { batchSize: 200 }
    });

结果虽然满足条件,但没有得到 item = journal 的文档

/* 1 */
{
    "item" : "paper",
    "instock" : [
        {
            "warehouse" : "A",
            "qty" : "60"
        },
        {
            "warehouse" : "B",
            "qty" : "15"
        }
    ]
},

/* 2 */
{
    "item" : "planner",
    "instock" : [
        {
            "warehouse" : "A",
            "qty" : "22"
        },
        {
            "warehouse" : "B",
            "qty" : "5"
        }
    ]
}

产品集合

[
    {
        "item": "journal",
        "instock": [
            {
                "warehouse": "A",
                "qty": "11"
            },
            {
                "warehouse": "C",
                "qty": "15"
            }
        ]
    },
    {
        "item": "paper",
        "instock": [
            {
                "warehouse": "A",
                "qty": "60"
            },
            {
                "warehouse": "B",
                "qty": "15"
            }
        ]
    },
    {
        "item": "planner",
        "instock": [
            {
                "warehouse": "A",
                "qty": "22"
            },
            {
                "warehouse": "B",
                "qty": "5"
            }
        ]
    }
]

在这种情况下,将不正确的结果作为大于运算符按字典顺序工作,但它应该像整数一样工作。虽然我尝试将其转换为双倍,但我没有得到任何结果。

使用 $convert to double 进行查询没有结果

db.runCommand(
    {
        aggregate: "products", pipeline: [
            //{ $match: { "item": { $in: ["planner", "paper","journal"] } } },
            {
                $match: {
                    instock: {
                        $elemMatch: {
                            warehouse: "A",
                            qty: {
                                $gt: [
                                    {$convert:{ input: "$qty", to: "double" }}, 5]
                            }
                        }
                    }
                }
            },
            { $project: { _id: 0 } }],
        cursor: { batchSize: 200 }
    });

【问题讨论】:

  • 你为什么要像这样运行查询 :: db.runCommand 在管理员上,你可以只在数据库集合上运行查询而不是你在做什么,因为通常我们不这样做,在这种情况下你也不需要做任何转换,而且不需要为这个简单的任务使用聚合框架,只需使用.find() :-)
  • 用户在 UI 上以图形方式创建查询,他选择字段并对其应用运算符和过滤器..
  • 对集合执行查询与传递 runCommands 有什么关系?
  • 这些与数据结构屏幕有关。集合名称和列是动态的。因此,我们正在使用所有复杂的业务规则创建自定义查询,并在 db.runCommand 的帮助下在 Mongodb 中执行该查询。请建议是否有更好的方法。
  • 您在哪里通过代码或外壳执行查询?

标签: mongodb mongoose mongodb-query type-conversion aggregation-framework


【解决方案1】:

试试这个:

db.products.aggregate([
  {
    $unwind: "$instock"
  },
  {
    $match: {
      $expr: {
        $and: [
          {
            $eq: [
              "$instock.warehouse",
              "A"
            ]
          },
          {
            $gt: [
              {
                $toInt: "$instock.qty"
              },
              2
            ]
          }
        ]
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      item: {
        $first: "$item"
      },
      instock: {
        $push: "$instock"
      }
    }
  },
  {
    $project: {
      _id: 0
    }
  }
])

MongoPlayground

【讨论】:

  • 使用 $unwind 我可以将字符串字段转换为 Int,然后应用大于运算符来过滤掉结果。但是在检索结果时,我们将 i 序列化为产品数据模型,产品数据模型需要一个库存数组。所以这是另一个问题,因为当 instock 不再是数组时,我们无法将其序列化到模型中。因此,如果产品符合条件,那么我们应该返回该产品的完整库存数组,而不是库存数组的子集。
  • 我们正在使用 C# Mongo Driver 在 db.runCommand 方法的帮助下执行查询。由于现有代码将中断,因此无法更改数据模型。
  • @siddhantsrivastava 请试一试,如果MonogDB在执行过程中改变了数据类型,但返回结果作为你的数据模型,C#驱动会正确处理
【解决方案2】:

试试这个,它使用$filter 来保留有条件的对象:

db.runCommand(
    {
        aggregate: "products", pipeline: [
            { $match: { 'instock.warehouse': 'A' } },
            {
                $addFields: {
                    instockCheck: {
                        $filter: {
                            input: '$instock', as: 'each', cond: {
                                $and: [{ $gt: [{ $toInt: '$$each.qty' }, 2] },
                                { $eq: ['$$each.warehouse', 'A'] }]
                            }
                        }
                    }
                }
            }, { $match: { instockCheck: { $gt: [] } } }, { $project: { instockCheck: 0, _id: 0 } }],
        cursor: { batchSize: 200 }
   });

测试: MongoDB-Playground

【讨论】:

  • 未按预期工作,因为大于运算符按字典顺序处理字符串。稍后在 API 中,确切的查询以纯字符串形式形成,并使用 db.runCommand 在数据库上执行
  • @siddhantsrivastava :你能给我举一个失败的例子吗?我会说带有字母数字字符的字符串与仅带有数字的字符串不同!
  • @siddhantsrivastava :好的,如果您将过滤器作为字符串并使用 runCommands 直接执行字符串作为查询是可以的,但通常大多数应用程序不会这样做但不是问题,但你仍然认为比较字符串数字不适合您?
  • 它没有获取 item = Journal 的文档,尽管它满足条件。
  • @siddhantsrivastava :对不起,这是我的错误,更新的答案:-)
猜你喜欢
  • 2011-06-21
  • 2012-02-09
  • 2013-02-25
  • 2013-01-02
  • 1970-01-01
  • 1970-01-01
  • 2013-09-03
  • 2015-10-27
  • 1970-01-01
相关资源
最近更新 更多