SQL到MongoDB的转换

Posted

技术标签:

【中文标题】SQL到MongoDB的转换【英文标题】:SQL to mongodb conversion 【发布时间】:2014-06-11 21:40:35 【问题描述】:

我在 mongodb 中有两个字段,AB

我想在mongo中执行下面的sql查询

SELECT DISTINCT A FROM table WHERE B LIKE 'asdf'

编辑澄清

foo =
    bar: [
            baz:[
                ‘one’,
                ‘two'
            ]
        ,...
    ]

我想选择 bar.baz 包含“一”的不同 foo 对象。 查询:

db.runCommand(
    "distinct": "foo",
    "query": 
        “bar.baz": “one"
    ,
    "key": “bar.baz"
);

这个查询,奇怪的是,返回 bar.baz /doesnt/ 包含“一个”的 foo 对象。

【问题讨论】:

在您的 SQL 中,“A”是表名,而不是字段。您的意思是输入其他内容吗? 已修复。感谢您指出这个错误 我发布的问题是一个简化。请查看更详细的问题 【参考方案1】:

这里似乎对 MongoDB distinct 命令的工作方式或任何查询如何与数组一起工作存在误解。

我将考虑您实际上拥有的文档看起来像这样:



    "_id" : ObjectId("5398f8bf0b5d1b43d3e26816"),
    "bar" : [
        
            "baz" : [
                "one",
                "two"
            ]
        ,
        
            "baz" : [
                "three"
            ]
        ,
        
            "baz" : [
                "one",
                "four"
            ]
        
    ]

所以你运行的查询,这两种形式是等价的:

db.runCommand( 
    "distinct": "foo", 
    "query":  "bar.baz": "one" , 
    "key": "bar.baz" 
)

db.foo.distinct("bar.baz",  "bar.baz": "one" )

基本上返回这个:

[ "four", "one", "three", "two" ]

为什么?好吧,因为你要求它。让我们考虑一种描述您实际调用的内容的声明方式。

你的“查询”本质上是说'找到所有“bar.baz”等于“one”的“文档”'然后你问'然后把所有的都还给我“bar.baz”的“不同”值

因此,您的语句的“查询”部分正是这样做的,并且匹配了“文档”,而不是与您指定的值匹配的数组成员。在上面的示例中,您随后要求“bar.baz”的“不同”值,这正是您得到的,只有“一个”的值从“bar.baz”的所有值返回一次”。

所以“查询”语句不会“过滤”数组内容,它们只是“匹配”条件存在的地方。上述文档符合条件,“bar.baz”的值为“one”,甚至两次。所以选择不同的“foo”或者基本上是文档真的是:

db.foo.find( "bar.baz": "one" )

匹配所有满足条件的文档。这就是嵌入的工作方式,但也许您想要过滤结果之类的东西。因此,如果只返回那些“baz”值为“one”的“bar”项目,您会这样做:

db.collection.aggregate([
    // Matches documents
     "$match":  "bar.baz": "one"  ,

    // Unwind to de-normalize arrays as documents
     "$unwind": "$bar" ,

    // Match to "filter" documents without "bar.baz" matching "one"
     "$match":  "bar.baz": "one"  ,

    // Maybe group back to document with the array
     "$group": 
        "_id": "$_id",
        "bar":  "$push": "$bar" 
    

])

这个.aggregate() 语句的结果是没有“bar”成员且“baz”下不包含“one”的文档:



    "_id" : ObjectId("5398f8bf0b5d1b43d3e26816"),
    "bar" : [
        
            "baz" : [
                "one",
                "two"
            ]
        ,
        
            "baz" : [
                "one",
                "four"
            ]
        
    ]

但是假设您实际上只希望元素“bar.baz”等于“one”以及这些出现在整个集合中的总数,那么您会想要这样做:

db.collection.aggregate([
    // Matches documents
     "$match":  "bar.baz": "one"  ,

    // Unwind to de-normalize arrays as documents
     "$unwind": "$bar" ,

    // And the inner array as well
     "$unwind": "$bar.baz" ,

    // Then just match and filter out everything but the matching items
     "$match":  "bar.baz": "one"  ,

    // Group to get the count
     "$group": 
        "_id": "$bar.baz",
        "count":  "$sum": 1 
    

])

您可以从我们的单一文档收集示例中获得:

 "_id": "one", "count": 2 

因为该匹配值出现了两次。


至于您的问题开头的 SQL,这确实不适用于此类数据。更实际的例子是这样的数据:

 "A": "A", "B": "BASDFJJ" 
 "A": "A", "B": "ASDFTT" 
 "A": "B", "B": "CASDF" 
 "A": "B", "B": "DKITB" 

所以“A”的“不同”值,其中“B”类似于“ASDF”,再次使用聚合并注意您在任何一方都没有通配符:

db.foo.aggregate([
     "$match":  "B": "ASDF"  ,
     "$group":  "_id": "$A"  
])

本质上产生:

 "_id": "A" 

或者在 "%ASDF%" 两边使用通配符,这是要匹配的 $regex 查询:

db.foo.aggregate([
     "$match":  "B":  "$regex": "ASDF"   ,
     "$group":  "_id": "$A"  
])

所以只有两个结果:

 "_id": "A" 
 "_id": "B" 

如果您“计算”不同的匹配项,那么根据匹配的文档,您会看到 2 和 1 分别作为计数。

进一步查看文档中包含的SQL Mapping Chart 和SQL to Aggregation Mapping Chart。它应该可以帮助您了解常见操作的实际转化方式。

【讨论】:

以上是关于SQL到MongoDB的转换的主要内容,如果未能解决你的问题,请参考以下文章

sql子查询到mongodb

C#-SQL到C#-MongoDB的转换。没有用于C#-MongoDB的DataAdapter?

在执行从 sql 到 mongodb 的 etl 时,十进制字段正在转换为 int32

将 SQL 表转换为 mongoDB 文档

MongoDB :: 将 SQL 转换为 MongoDB

将此 SQL 查询转换为 mongodb 查询 -