5

MySQLが私を狂わせているので、私は自分の最初の「NoSQL」DBMSに精通しようとしていますが、それはたまたまMongoDBでした。rmongodbを介して接続しています。

rmongodbをいじくり回すほど、高度なクエリの実行に関してより多くの質問/問題が発生します。

正しく指定できないと思われるさまざまなタイプのクエリについて詳しく説明する前に、まずいくつかのサンプルデータを示します。

サンプルデータ

この例はMongoDBWebサイトから抜粋したもので、少し簡略化されています。

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オブジェクトの挿入に関連する2つの質問:

  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" 

質問1:基本的なサブレベルのクエリ

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
4

3 に答える 3

7

c()またはlist()のどちらでも問題ありません。コンポーネントに名前が付けられているかどうか、およびすべてのコンポーネントが同じタイプ(リスト用)であるかどうかによって異なります。最善の方法は、生成されたBSONを調べて、必要なものが得られているかどうかを確認することです。生成されたオブジェクトを最適に制御するには、mongo.bson.bufferとそれを操作する関数を使用します。実際、これがサブクエリが失敗する理由です。「コメント」は、配列ではなくサブオブジェクトとして作成されています。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は点線の名前を窒息させるので、ここでは必ずバッファを使用する必要があることに注意してください。

これで問題が解決することを願っています。ご不明な点がございましたら、お気軽にお問い合わせください。

于 2012-06-09T14:12:25.180 に答える
2

質問が投稿された後、SOで進行するための好ましい方法についてはまだよくわかりませんが、もう少し詳しく説明し、さらに質問と回答のアプローチを追加したいと考えています。

元の質問を将来の編集で爆破しないように言われることがよくあるので、この「回答」では、Gerald Lindslyの提案を取り入れて、実際のコードに入れようとしています(まだうまくいかなかったため) )::

準備

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)

# Make sure we start with an empty collection
mongo.drop(mongo, paste(db, ns, sep="."))

ドキュメントを挿入

ジェラルドが彼の答えで指摘しているmongo.bson.from.list()ように、結果のBSON構造について間違った推測をすることがあるので、明示的にBSON配列オブジェクトを作成しようとしました。

buf <- mongo.bson.buffer.create()

# 'REGULAR' APPENDING
mongo.bson.buffer.append(buf, "_id", "abcd")
mongo.bson.buffer.append(buf, "when", 
    mongo.timestamp.create(strptime("2011-09-19 02:00:00",
        "%Y-%m-%d %H:%M:%s"), increment=1))
mongo.bson.buffer.append(buf, "author", "alex")
mongo.bson.buffer.append(buf, "title", "Some title")
mongo.bson.buffer.append(buf, "text", "Some text.")
mongo.bson.buffer.append(buf, "tags", c("tag.1", "tag.2"))
mongo.bson.buffer.append(buf, "votes", 5)
# /

# VOTERS ARRAY
mongo.bson.buffer.start.array(buf, "voters")
voters <- c("jane", "joe", "spencer", "phyllis", "li")
i=1
for (i in seq(along=voters)) {
    mongo.bson.buffer.append(buf, as.character(i), voters[i])
}
mongo.bson.buffer.finish.object(buf)
# /

# COMMENTS ARRAY
mongo.bson.buffer.start.array(buf, "comments")

mongo.bson.buffer.start.object(buf, "1")
mongo.bson.buffer.append(buf, "who", "jane")
mongo.bson.buffer.append(buf, "when", 
    mongo.timestamp.create(strptime("2011-09-19 04:00:00",
            "%Y-%m-%d %H:%M:%s"), increment=1))
mongo.bson.buffer.append(buf, "comment", "some comment.")
mongo.bson.buffer.finish.object(buf)

mongo.bson.buffer.start.object(buf, "2")
mongo.bson.buffer.append(buf, "who", "meghan")
mongo.bson.buffer.append(buf, "when", 
    mongo.timestamp.create(strptime("2011-09-20 13:00:00",
            "%Y-%m-%d %H:%M:%s"), increment=1))
mongo.bson.buffer.append(buf, "comment", "some comment.")
mongo.bson.buffer.finish.object(buf)
# /

# FINALIZE
mongo.bson.buffer.finish.object(buf)
b <- mongo.bson.from.buffer(buf)
> b
_id : 2      abcd
when : 17    i: 1, t: 1316390400
author : 2   alex
title : 2    Some title
text : 2     Some text.
tags : 4     
    0 : 2    tag.1
    1 : 2    tag.2

votes : 1    5.000000
voters : 4   
    1 : 2    jane
    2 : 2    joe
    3 : 2    spencer
    4 : 2    phyllis
    5 : 2    li

comments : 4     
    1 : 3    
        who : 2      jane
        when : 17    i: 1, t: 1316397600
        comment : 2      some comment.

    2 : 3    
        who : 2      meghan
        when : 17    i: 1, t: 1316516400
        comment : 2      some comment.

mongo.insert(mongo, "test.posts", b)

基本的なサブレベルのクエリ

# 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

ドキュメントを指定するとき、私はまだここで何か間違ったことをしているに違いありません;-)

于 2012-06-12T10:18:09.440 に答える
2

アトミッククエリと$in演算子に関して、最初の質問からクエリ2を次のように機能させました。

buf <- mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "test")
mongo.bson.buffer.start.array(buf, "$in")
mongo.bson.buffer.append(buf, "a", "a")
mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.finish.object(buf)
criteria <- mongo.bson.from.buffer(buf)
criteria

配列が1つの要素のみを保持することになった場合、配列を明示的に開始および終了することでうまくいくと思います。

便利なことの1つは、mongodコンソールまたはログを監視することです(-vオプションでmongodを起動した後)。古いクエリを実行すると、次のように表示されます。

Tue Nov 20 16:09:04 [conn23] User Assertion: 12580:invalid query
Tue Nov 20 16:09:04 [conn23] assertion 12580 invalid query ns:test.users query:{ test: { $in: "a" } }
Tue Nov 20 16:09:04 [conn23] problem detected during query over test.users : { $err: "invalid query", code: 12580 }
Tue Nov 20 16:09:04 [conn23] query test.users query: { test: { $in: "a" } } ntoreturn:0 keyUpdates:0 exception: invalid query code:12580 locks(micros) r:440 reslen:59 0ms

変更されたクエリを実行すると、問題ないように見えます。

Tue Nov 20 16:10:14 [conn23] query test.users query: { test: { $in: [ "a" ] } } ntoreturn:0 keyUpdates:0 locks(micros) r:168 nreturned:1 reslen:142 0ms
于 2012-11-21T00:10:39.527 に答える