问题:在 R 中使用 rmongodb 运行高级 MongoDB 查询

由于 MySQL 让我发疯,我试图让自己熟悉我的第一个“NoSQL”DBMS,它恰好是MongoDB。我通过rmongodb连接到它。

我玩的越多rmongodb,关于运行高级查询的问题/问题就越多。

首先,在详细介绍我似乎无法正确指定的不同类型的查询之前,我先介绍一些示例数据。

示例数据

该示例取自MongoDB 网站并进行了一些简化。

pkg <- "rmongodb"
if (!require(pkg, character.only=TRUE)) {
    install.packages(pkg)
    require(pkg, character.only=TRUE)   
}

# Connect to DB
db <- "test"
ns <- "posts"
mongo <- mongo.create(db=db)

# Insert document to collection 'test.users'
b <- mongo.bson.from.list(list(
    "_id"="alex", 
    name=list(first="Alex", last="Benisson"),
    karma=1.0,
    age=30,
    test=c("a", "b")
))
mongo.insert(mongo, "test.users", b)

# Insert document to collection 'test.posts'
b <- mongo.bson.from.list(list(
        "_id"="abcd",
        when=mongo.timestamp.create(strptime("2011-09-19 02:00:00",
            "%Y-%m-%d %H:%M:%s"), increment=1),
        author="alex",
        title="Some title",
        text="Some text.",
        tags=c("tag.1", "tag.2"),
        votes=5,
        voters=c("jane", "joe", "spencer", "phyllis", "li"),
        comments=list(
            list(
                who="jane", 
                when=mongo.timestamp.create(strptime("2011-09-19 04:00:00",
                    "%Y-%m-%d %H:%M:%s"), increment=1),
                comment="Some comment."
            ),
            list(
                who="meghan", 
                when=mongo.timestamp.create(strptime("2011-09-20 13:00:00",
                    "%Y-%m-%d %H:%M:%s"), increment=1),
                comment="Some comment."
            )
        )
    )
)
b
mongo.insert(mongo, "test.posts", b)

与插入 JSON/BSON 对象相关的两个问题:

1.文档'test.posts',字段voters:这种情况下使用c()是否正确?

2.文档'test.posts',字段comments:指定这个的正确方法是什么,c()还是list()?

顶级查询:他们很享受

顶级查询工作得很好:

# Get all posts by 'alex' (only titles)
res <- mongo.find(mongo, "test.posts", query=list(author="alex"), 
    fields=list(title=1L))
out <- NULL
while (mongo.cursor.next(res))
    out <- c(out, list(mongo.bson.to.list(mongo.cursor.value(res))))

> out
[[1]]
                       _id                      title 
                     "abcd"            "No Free Lunch" 

问题一:基本子级查询

如何运行需要进入JSON/BSON样式 MongoDB 对象的任意深度子级别的简单“子级别查询”(与顶级查询相反)?这些子级别查询使用 MongoDB 的点表示法我似乎无法弄清楚如何将其映射到有效的rmongodb查询

在简单的 MongoDB 语法中,类似于

> db.posts.find( { comments.who : "meghan" } )

会工作。但我不知道如何用rmongodb函数做到这一点

这是我到目前为止尝试过的

# Get all comments by 'meghan' from 'test.posts'

#--------------------
# Approach 1)
#--------------------
res <- mongo.find(mongo, "test.posts", query=list(comments=list(who="meghan")))
out <- NULL
while (mongo.cursor.next(res))
    out <- c(out, list(mongo.bson.to.list(mongo.cursor.value(res))))

> out
NULL
# Does not work

#--------------------
# Approach 2) 
#--------------------
buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "comments")
mongo.bson.buffer.append(buf, "who", "meghan")
mongo.bson.buffer.finish.object(buf)
query <- mongo.bson.from.buffer(buf)
res <- mongo.find(mongo, "test.posts", query=query)
out <- NULL
while (mongo.cursor.next(res))
    out <- c(out, list(mongo.bson.to.list(mongo.cursor.value(res))))

> out
NULL
# Does not work

问题2:使用$运算符进行查询

这些工作

查询 1

buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "age")
mongo.bson.buffer.append(buf, "$lte", 30)
mongo.bson.buffer.finish.object(buf)
criteria <- mongo.bson.from.buffer(buf)
criteria

> mongo.find.one(mongo, "test.users", query=criteria)
    _id : 2      alex
    name : 3     
        first : 2    Alex
        last : 2     Benisson

    karma : 1    1.000000
    age : 1      30.000000
    test : 4     
        0 : 2    a
        1 : 2    b

查询 2

buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "test")
mongo.bson.buffer.append(buf, "$in", c("a", "z"))
mongo.bson.buffer.finish.object(buf)
criteria <- mongo.bson.from.buffer(buf)
criteria
mongo.find.one(mongo, "test.users", query=criteria)

但是,请注意,原子集将导致返回值NULL

mongo.bson.buffer.append(buf, "$in", "a")
# Instead of 'mongo.bson.buffer.append(buf, "$in", c("a", "z"))'

尝试与子级别查询相同,我又迷路了

buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "name")
mongo.bson.buffer.start.object(buf, "first")
mongo.bson.buffer.append(buf, "$in", c("Alex", "Horst"))
mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.finish.object(buf)
criteria <- mongo.bson.from.buffer(buf)
criteria <- mongo.bson.from.buffer(buf)
> criteria
    name : 3     
        first : 3    
            $in : 4      
                0 : 2    Alex
                1 : 2    Horst

> mongo.find.one(mongo, "test.users", query=criteria)
NULL

解答

c() 或 list() 都可以。取决于组件是否命名以及它们是否都具有相同的类型(对于列表)。最好的办法是查看生成的 BSON,看看你是否得到了你想要的。为了最好地控制生成的对象,请使用 mongo.bson.buffer 和对其进行操作的函数。事实上,这就是子查询失败的原因。 'comments' 被创建为子对象而不是数组。 mongo.bson.from.list() 很方便,但它不能给你相同的控制,有时它会猜错从复杂结构中生成的内容。

可以像这样更正对另一组数据的查询:

buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "name.first")
mongo.bson.buffer.append(buf, "$in", c("Alex", "Horst"))
mongo.bson.buffer.finish.object(buf)
criteria <- mongo.bson.from.buffer(buf)

请注意,您肯定需要在此处使用缓冲区,因为 R 会因虚线名称而窒息。

我希望这能解决你的问题。如果您还有其他问题,请告诉我。

Logo

MongoDB社区为您提供最前沿的新闻资讯和知识内容

更多推荐