21

この質問はこれと密接に関連しており、NoSQL コンテキストでのスキーマ設計に関して与えられたアドバイスを検討しますが、これを理解したいと思っています。

実際の質問

次のドキュメントがあるとします。

    _id : 2      abcd
    name : 2     unittest.com
    paths : 4    
        0 : 3    
            path : 2     home
            queries : 4      
                0 : 3    
                    name : 2     query1
                    url : 2      www.unittest.com/home?query1
                    requests: 4

                1 : 3    
                    name : 2     query2
                    url : 2      www.unittest.com/home?query2
                    requests: 4

基本的に知りたい

  1. MongoDB の位置$演算子 ( details ) を複数回使用できる場合、または別の言い方をすれば、「ネスト度」が 1 より大きい配列/ドキュメント構造を含む更新シナリオで:

    { <update operator>: { "paths.$.queries.$.requests" : value } }(動作しません)

    $ トップレベルの配列に「のみ」使用でき、「より高いレベル」の配列に明示的なインデックスを使用するようにバインドされる代わりに:

    { <update operator>: { "paths.$.queries.0.requests" : value } }) (作品)

  2. 可能であれば、対応する R 構文がどのように見えるか。

以下に、再現可能な例を示します。できるだけ簡潔にしようとしました。


コード例

データベース接続

require("rmongodb")
db  <- "__unittest" 
ns  <- paste(db, "hosts", sep=".")
# CONNCETION OBJECT
con <- mongo.create(db=db)
# ENSURE EMPTY DB
mongo.remove(mongo=con, ns=ns)

文書例

q <- list("_id"="abcd")
b <- list("_id"="abcd", name="unittest.com")
mongo.insert(mongo=con, ns=ns, b=b)
q <- list("_id"="abcd")
b <- list("$push"=list(paths=list(path="home")))
mongo.update(mongo=con, ns, criteria=q, objNew=b)
q <- list("_id"="abcd", paths.path="home")
b <- list("$push"=list("paths.$.queries"=list(
    name="query1", url="www.unittest.com/home?query1")))
mongo.update(mongo=con, ns, criteria=q, objNew=b)
b <- list("$push"=list("paths.$.queries"=list(
    name="query2", url="www.unittest.com/home?query2")))
mongo.update(mongo=con, ns, criteria=q, objNew=b)

明示的な位置インデックスを使用したネストされた配列の更新 (機能)

これは機能しますが、第 2 レベルの配列( array の subdoc 要素にネストされている) の明示的なインデックスが必要です。queriespaths

q <- list("_id"="abcd", paths.path="home", paths.queries.name="query1")
b <- list("$push"=list("paths.$.queries.0.requests"=list(time="2013-02-13")))
> mongo.bson.from.list(b)
    $push : 3    
        paths.$.queries.0.requests : 3   
            time : 2     2013-02-13

mongo.update(mongo=con, ns, criteria=q, objNew=b)
res <- mongo.find.one(mongo=con, ns=ns, query=q)
> res
    _id : 2      abcd
    name : 2     unittest.com
    paths : 4    
        0 : 3    
            path : 2     home
            queries : 4      
                0 : 3    
                    name : 2     query1
                    requests : 4     
                        0 : 3    
                            time : 2     2013-02-13


                    url : 2      www.unittest.com/home?query1

                1 : 3    
                    name : 2     query2
                    url : 2      www.unittest.com/home?query2

位置インデックスを使用したネストされた配列の更新$(機能しません)

ここで、サーバーに配列( )の目的のサブドキュメント要素を見つけさせるために、私が行ったのと同じように、明示的なもの0を位置演算子に置き換えたいと思います。$pathspaths.$.queries

AFAIUドキュメント、これは重要なことは「正しい」クエリセレクターを指定することであるため、機能するはずです。

位置 $ 演算子は update() メソッドで使用され、更新クエリ セレクターの最初の一致のプレースホルダーとして機能します。

正しいネストされた要素を見つけるクエリセレクターを指定したと思います(一部のためpaths.queries.name="query1"

q <- list("_id"="abcd", paths.path="home", paths.queries.name="query1")

「プレーンなMongoDB」構文に翻訳すると、クエリセレクターは次のようになります

{ _id: abcd, paths.path: home, paths.queries.name: query1 }

これは有効なクエリ セレクターのように思えます。実際、目的の要素/ドキュメントと一致します:

> !is.null(mongo.find.one(mongo=con, ns=ns, query=q))
[1] TRUE

私の考えでは、トップレベルで機能する場合、(クエリセレクターが適切なネストされたコンポーネントを指している限り) より高いレベルでも機能しないのはなぜでしょうか?

ただし、サーバーはネストされたまたは複数の使用を好まないようです$:

b <- list("$push"=list("paths.$.queries.$.requests"=list(time="2013-02-14")))
> mongo.bson.from.list(b)
    $push : 3    
        paths.$.queries.$.requests : 3   
            time : 2     2013-02-14

> mongo.update(mongo=con, ns, criteria=q, objNew=b)
[1] FALSE

MongoDB がこれをサポートしていないために機能しないのか、それとも R 構文を正しく理解していなかったのかはわかりません。

4

2 に答える 2

5

MongoDB シェルからクエリを実行できる場合は、MongoDB カーソルのforEach関数 ( http://docs.mongodb.org/manual/reference/method/cursor.forEach/ )を利用して、この制限を回避できます。

以下は、ネストされた 3 つの配列の例です。

var collectionNameCursor = db.collection_name.find({...});

collectionNameCursor.forEach(function(collectionDocument) {
    var firstArray = collectionDocument.firstArray;
    for(var i = 0; i < firstArray.length; i++) {
        var secondArray = firstArray[i].secondArray;
        for(var j = 0; j < secondArray.length; j++) {
            var thirdArray = secondArray[j].thirdArray;
            for(var k = 0; k < thirdArray.length; k++) {
                //... do some logic here with thirdArray's elements
                db.collection_name.save(collectionDocument);
            }
        }
    }
});

これは、本番コードよりも 1 回限りの解決策ですが、修正スクリプトを作成する必要がある場合は、これで十分です。

于 2013-09-10T14:30:50.263 に答える