sql >> データベース >  >> NoSQL >> MongoDB

$exprarrayElementAtが埋め込みドキュメントの集計で機能しない

    クイックフィックス

    ここでは「パイプライン」は機能しません主に 最初の $project 後の段階で使用したいフィールドがありません。 「クイックフィックス」 したがって、基本的には、そのフィールドを「投影された」ドキュメントに含める必要があります。これは、集約パイプラインステージがどのように機能するかを示しているためです。

    array(
      array(
        '$project' => array(
          'FullName' => array('$concat' => array('$first_name', ' ', '$middle_name', ' ', '$last_name')),
          'FirstMiddle' => array('$concat' => array('$first_name', ' ', '$middle_name')),
          'FirstLast' => array('$concat' => array('$first_name', ' ', '$last_name')),
          'FirstName' => array('$concat' => array('$first_name')),
          'MiddleName' => array('$concat' => array('$middle_name')),
          'LastName' => array('$concat' => array('$last_name')),
          'Student' => '$$ROOT',
          'allotment_details' => 1 # that's the change
        )
      ),
    

    または、$$ROOTを使用した場合でも Studentの場合 とにかく、そのパスの下のフィールドを修飾するだけです:

    '$expr' => array(
      '$eq'=> array(
        array('$arrayElemAt' => array('$Student.allotment_details.room_id', -1)),
        $this->RoomId
      )
    ),
    

    ただし 強く* しないことをお勧めします

    後で行うための「文字列の連結」の全体的な概念 $match 「フィルタリング」が実際に行われる前にコレクション全体がパイプラインで書き直されることを意味するため、コンテンツをオンにすることは非常に悪い考えです。

    同様に、「最後の」配列要素で一致するように探すことも問題です。はるかに優れたアプローチは、代わりに、「終了」ではなく、実際に「新しいアイテム」を配列の「開始」に追加することです。これは、実際には $position または、おそらく$sort $pushへの修飾子 アイテムを追加する場所やアイテムの並べ替え順序をそれぞれ変更することで、あなたに代わって行います。

    アレイを「最新のものから」に変更する

    これは、保存方法を変更することで少し手間がかかりますが、評価された$exprを必要とせずに、必要なクエリの速度が大幅に向上するという利点があります。 引数。

    コアコンセプトは、次のような構文で新しい配列アイテムを「プリペンド」することです。

    $this->collection->updateOne(
      $query,
      [ '$push' => [ 'allotment_details' => [ '$each' => $allotments, '$position' => 0 ] ] ]
    )
    

    $allomentsの場所 必須 $eachで必要とされる配列である および $position 0に使用されます 新しい配列アイテムを「最初に」追加するため。

    または、実際にcreated_dateのようなものがある場合 配列内の各オブジェクト内のプロパティとして、 $sort 代わりに修飾子として。

    $this->collection->updateOne(
      $query,
      [ '$push' => [
          'allotment_details' => [ '$each' => $allotments, '$sort' => [ 'created_date' => -1 ] ]
      ]]
    )
    

    これは、「クエリ」やその他のアクセス要件が「最終追加日」と「最新日」のどちらに依存しているかによって異なります。また、通常、このようなcreated_dateを変更する可能性があるかどうかによっても異なります。 または、「ソート」されたときに配列要素の順序に影響を与えるような方法でのその他の「ソート」プロパティ。

    これを行う理由は、配列内の「最新」(現在は「最初」)の項目を照合するためです。

    $this->collection->find([
     'allotment_details.0.room_id': $this->RoomId
    ])
    

    MongoDBでは、「最初の」配列インデックスを"DotNotation"で指定できます。 0を使用 索引。 できない 「負の」インデックスを指定することです。つまり、

    $this->collection->find([
     'allotment_details.-1.room_id': $this->RoomId  # not allowed :(
    ])
    

    これが、配列を実行可能な形式に「並べ替える」ために、上記の「更新」で行うことを行う理由です。

    連結が悪い

    もう1つの主要な問題は、文字列の連結です。すでに述べたように、これは必要なマッチングを行うためだけに不要なオーバーヘッドを作成します。 $orを使用してこれを完全に回避できるため、これも「不要」です。 実際のドキュメント内にすでに存在する各フィールドの条件を使用して:

     $this->collection->find([
       '$or' => [
           [ 'first_name' => new MongoDB\BSON\Regex($arg, 'i') ],
           [ 'last_name' => new MongoDB\BSON\Regex($arg, 'i') ],
           [ 'middle_name' => new MongoDB\BSON\Regex($arg, 'i') ],
           [ 'registration_temp_perm_no' => $arg ]
       ],
       'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
       'allotment_details.0.room_id': $this->RoomId
     ])
    

    そしてもちろん、「完全な」クエリ条件が実際に必要なものは何でも、基本的な考え方を理解しているはずです。

    また、実際に「部分的な単語」を探していない場合は、"テキスト検索" 「名前」でフィールド上に定義されます。次のようなインデックスを作成した後:

     $this->collection->find([
       '$text' => [ '$search' => $arg ],
       'schoolId' => new MongoDB\BSON\ObjectID($this->SchoolId),
       'allotment_details.0.room_id': $this->RoomId
     ])
    

    全体として、既存のコードに1つの小さな変更を加えるのではなく、他のすべてのオプションを詳しく調べることをお勧めします。物事の保存方法と実際に物事の「インデックス付け」方法を少し注意深く再構築することで、広範な$concatよりもパフォーマンスが大幅に向上します。 「ブルートフォース」アプローチでは、単純に実現できません。




    1. 文字列をMongoDBのObjectIDに変換します

    2. RedisとMongoDB

    3. MongoDB全文検索とLucene?

    4. MongoDBのプッシュとルートに相当するC#とは何ですか?