SQL到MongoDB的转换
Posted
技术标签:
【中文标题】SQL到MongoDB的转换【英文标题】:SQL to mongodb conversion 【发布时间】:2014-06-11 21:40:35 【问题描述】:我在 mongodb 中有两个字段,A
和 B
我想在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的转换的主要内容,如果未能解决你的问题,请参考以下文章
C#-SQL到C#-MongoDB的转换。没有用于C#-MongoDB的DataAdapter?