MongoDB入門3ステップ2-基本操作(続き):集約、インデックス、カーソル、mapReduce

7783 ワード

mongodb基本操作(続き)--集約、インデックス、カーソル、mapReduce
目次
  • 集約アクション
  • MapReduce
  • カーソル
  • 索引

  • 集約アクション
    ほとんどのリレーショナル・データベースのように、Mongodbは集約操作も提供するが、ここでは一般的ないくつかの集約操作のみを列挙する:Countカウントはdbのようである.collection.find()操作は条件を満たすレコードを返すことができるようにdb.collection.count()は、条件を満たすレコード数を返します.
    db.blog.count({"title":"mongo"}) 
    
    

    このコマンドは、blogセット内のtitle=「mongo」のレコード数を返します.
    Distinctはdbを定義する.collection.distinct(keyword,condition)から分かるように、distinctはクエリ条件conditionに基づいて結果のフィールドkeywordをデウェイトし、conditionを指定しない場合、全表クエリ後にkeyworldをデウェイトし、例は以下の通りである.
    db.blog.distinct("author")
    
    

    このコマンドは、blogセットで繰り返されないauthor値を返します.ある日2014-02-26に発表された文章の著者がクエリーしたように、クエリー時に条件を付けたい場合があります.例えば、次のコマンドでいいです.
    db.blog.distinct("author", {"create":"2014-02-26"}) 
    
    

    もちろん、返される結果はjsのリストデータであるため、リストの長さを統計するだけです.
    db.blog.disinct("author").length 
    
      
    
    var authors = db.blog.distinct("author")
    
    authors.length
    
    

    groupパケットはmysqlのような関係データベースを使用したことがある友人は知っているはずだが、mysqlではgroupはクエリ結果をあるフィールドでパケット化して再編成した後にクエリに戻るデータリストであり、すなわち返されるデータは依然として1本1本であり、元のデータベーステーブルのパターンを変更せず、結果に記録された各記録の前後の順序を調整しただけである.mongodbでは、パケットもkeyと呼ばれる使用フィールドを指定する必要があります.mysqlとは異なり、同じkeyを持つデータ格納場所を指定する必要があります.通常、配列、すなわち結果に対するinitialです.最後に、結果セットに配置するフィールドも指定します.例を次に示します.
    db.blog.group({
    
      "key":{"author":true},
    
      "initial":{"blog":[]},
    
      "$reduce":function(doc,aggregation){
    
        aggregation.blog.push({"title":doc.title,"create":doc.create});
    
      },
    
      "condition":{"create":{$gte:"2014-01-01"}},
    
      "finalize":function(aggregation){
    
        aggregation.count=aggregation.blog.length; 
    
      }
    
    })
    
    

    上記のコマンドはauthorに基づいてグループ化され、各レコードのtitleフィールドとcreateフィールドはグループ集約情報に格納されます.$reduce関数を定義するには、次の2つのパラメータを指定する必要があります.
  • doc現在の動作の記録
  • aggregationキーでグループ化された集約情報は$reduceに対して、上で調べた情報を追加できるほか、あるフィールドの統計値を計算するなど、多くの操作を実行することができます.シーンによって方法が異なります.group操作におけるconditionおよびfinalizeパラメータは必須ではありませんが、場合によっては非常に有用です.
  • conditionはgroup動作に条件フィルタリングを提供し、create>='2014-01-01'の記録のみをパケット統計
  • とした.
  • finalizeは、各グループのドキュメントパケットが完了した後にタッチし、上記のコマンドでは、各パケットが完了した後に各パケットの数を統計しcountフィールドに出力します.

  • MapReduce
    MapReduceは分散計算のプログラミングモデルで、各データを異なるパケットにマッピングするmap関数を指定し、reduceは各グループを計算します.したがってmongodbでは,MapReduceは集約関数の複雑なシーンと見なすこともできる.最も簡単なmapReduce呼び出しには、map、reduce、および結果が出力される集合の3つのパラメータが必要です.
    db.blog.mapReduce(
    
      function(){emit(this.author, {author:this.author,count:1});},
    
      function(key, values){
    
        var result = {"author":"", "count":0};
    
        for(var i = 0, i < values.length; i++) {
    
          result.count += values[i].count;
    
          result.author = values[i].author;
    
        }
    
        return result;
    
      },
    
      {"out":"authorStatistics"}
    
    )
    
    

    OK、この文を実行すると、idとvalueの2つのトップフィールドがあり、idの値はkeyに対応する値であり、valueにはresultで定義されたようにサブjsonレイヤがある新しい集合authorStatisticsが得られます.
    { "_id" : "enjiex", "value" : { "author" : "enjiex", "count" : 1 } }
    
    { "_id" : "enjiex1", "value" : { "author" : "enjiex1", "count" : 2 } }
    
    

    次にmapおよびreduce関数について重点的に説明します.
  • map関数:map関数でemit関数が呼び出されます.この関数には、keyとvalueの2つのパラメータがあります.keyはデータパケットのパケットフィールドであり、valueは計算に参加する必要がある値列に対応します.たとえば、上記のプログラムの値列は{name:this.author,count:1}であり、1つのデータをこのメソッドで呼び出すと、中間値が生成されます.
    {"key":"enjiex", "value":{"author":"enjiex", "count":1}}


  • すべてのクエリー・データをmapメソッドで呼び出すと、同様の中間結果が生成されます.
    [{"key":"enjiex",
    
      "value":[
    
        {"author":"enjiex","count":1},
    
        {"author":"enjiex","count":1}
    
      ]
    
     },
    
     {"key":"mc",
    
      "value":{"author":"enjiex","count":1}}
    
    ]
    
    

    この中間結果は,emit内のvalueをkeyでグループ化したデータの集合であることがわかる.
  • reduce関数:keyとvaluesの2つのパラメータがあり、keyの意味はemitの意味と同じであり、valuesはmapメソッドによって生成された中間結果に対応します.reduce関数では中間結果を再処理し,上記の手順では中間結果のcountフィールドのみを和計算した.
  • 結果出力:mapReduceメソッドの最後のパラメータ:{"out":"authorStatistics"}は、結果セットの出力位置がauthorStatisticsであることを示し、呼び出しが実行されると現在のライブラリの下にauthorStatisticsというセットが生成されます.

  • カーソル
    カーソルコンセプトはmongo shellでdbを実行する.blog.find()は、すぐに結果をshellウィンドウに出力しますが、db.blog.find()は変数に割り当てられます.
    var blogs = db.blog.find()
    
    

    ではblogsは実はmongodbから戻ってきたカーソルを手に入れました.カーソルを手に入れると違うことができます.最も簡単なのはmongo shellでdbを実行することです.blog.find()効果のような遍歴出力--shellでdbを直接実行する.blog.find()もカーソルを返したが、shellはデータを遍歴して出力してくれた.
    var blogs = db.blog.find()
    
    while(blogs.hasNext()) {
    
      var blog = blogs.next();
    
      print(blog.title)
    
    }
    
    

    上記のコードでは、blogsはカーソルであり、blogsを呼び出す.hasNext()の場合、デフォルトではデータベースから100件のドキュメントが一括して読み込まれ、blogsが呼び出されます.next()の場合、現在の位置のレコードが返されます.カーソル操作は、カーソルに対してhasNext()およびnext()操作を実行するほか、カーソルに対してlimit、skipおよびsort操作を実行することもできます.
  • limit:カーソルの戻り数、すなわちデータの戻り上限を制限します.
  • skip:返された結果の最初のデータが無視されたかを指定し、ドキュメントの総数がskipの数値より小さい場合、空のセットを返します.
  • sort:得られたセットを指定したフィールドでソートします.カーソル上で上記の操作を実行してもカーソルが返されるため、カーソル上でメソッドチェーンで呼び出すことができます.
    var blogs = db.blog.find();
    
    blogs.limit(100).skip(10),sort({"author":1,"create":1})
    
    

    上記のコードは、戻りデータ量を100に制限してから、最初の10のデータ(実際に有効なデータは90のデータ)をスキップし、authorとcreateでソートします.実は上のコードはあまり有効ではありません.10件の記録を無駄にしたので、下の書き方がいいかもしれません.
    db.blog.find().skip(10).limit(100).sort({"author":1,"create":1});
    
    

    この実際に返される有効なデータは100個です.

  • 索引
    インデックスベースインデックスは、データ・クエリーの効率を向上させる有効な手段であり、一般的なフィールドまたはフィールドの組合せにインデックスを作成することで、そのフィールドまたはフィールドの組合せにおけるクエリーの効率を向上させることができます.インデックスを簡単に作成する方法:
    db.blog.ensuerIndex({"author":1}) 
    
    

    以上の方法により、blogセットのauthorフィールドにシーケンスインデックスが作成されます(authorの値は、元のデータレコードへの参照を維持しながらBツリーに割り当てられます).その後author条件クエリを通過すると、このインデックスツリーで検索し、最終データレコードを返します.しかし、インデックスを作成することで、クエリーの効率は本当に向上しましたか?インデックスの作成前後に、クエリー・オペレーションが遍歴するレコードの数をexplainメソッドで表示できます.
    db.blog.find({"author":"enjiex"}).explain()
    
    

    インデックスを作成すると、同じライブラリの下にsystemが1つ追加されます.indexesコレクション.現在のライブラリ内のすべてのインデックス作成情報が格納されます.dbを通過する.system.indexes.find()は、現在のライブラリの下にどのインデックスレコードがあるかを表示します.
    ユニークインデックスblogコマンドでauthorごとに1つの文章しか発表できない場合、つまりauthorごとの値がblogレコードに1回しか現れない場合は、ユニークインデックスを作成することでよい.
    db.blog.ensuerIndex({"author":1}, {"unique":true}) 
    
    

    なお、blogセットに同じauthorの複数のレコードが既に表示されている場合、上記のコマンドは成功せず、重複レコードを手動で削除してから実行するしかありません.
    インデックスを組み合わせて一意のインデックスの前のシーンに戻ると、authorごとに多くの記事が発表される可能性がありますが、authorのある日の記事を常にクエリーする必要があります.authorとcreateに組み合わせインデックスを作成するだけで、このクエリの効率が向上します.
    db.blog.ensureIndex({"name":1, "birthday":1})
    
    

    mongodbにとって,{"name":1,"birthday":1}と{"birthday":1,"name":1}は異なるインデックスであるため,インデックスを作成する際には必ず実際のクエリーシーンと結びつけて正確に処理しなければならない.クエリーの場合、独自に作成したインデックスが使用されているかどうかが不明な場合は、explain()と組み合わせてクエリーの詳細を表示できます.インデックスを削除すると、このように多くのインデックスが作成されますが、ビジネスが変化するにつれて、一部のインデックスは不要になり、維持を続けると不要なオーバーヘッドが増加する場合は、無効なインデックスをタイムリーに消去します.
    db.blog.dropIndexes("index_name") 
    
    

    dropIndexesを呼び出し、削除するインデックス名を指定します.インデックス名はずっと言われていませんが、一言で検索できます.
    db.blog.getIndexes()