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

MongoDB集約フレームワークを使用して一次導関数を計算する

    db.collection.aggregate(
        [
          {
            "$addFields": {
              "indexes": {
                "$range": [
                  0,
                  {
                    "$size": "$time_series"
                  }
                ]
              },
              "reversedSeries": {
                "$reverseArray": "$time_series"
              }
            }
          },
          {
            "$project": {
              "derivatives": {
                "$reverseArray": {
                  "$slice": [
                    {
                      "$map": {
                        "input": {
                          "$zip": {
                            "inputs": [
                              "$reversedSeries",
                              "$indexes"
                            ]
                          }
                        },
                        "in": {
                          "$subtract": [
                            {
                              "$arrayElemAt": [
                                "$$this",
                                0
                              ]
                            },
                            {
                              "$arrayElemAt": [
                                "$reversedSeries",
                                {
                                  "$add": [
                                    {
                                      "$arrayElemAt": [
                                        "$$this",
                                        1
                                      ]
                                    },
                                    1
                                  ]
                                }
                              ]
                            }
                          ]
                        }
                      }
                    },
                    {
                      "$subtract": [
                        {
                          "$size": "$time_series"
                        },
                        1
                      ]
                    }
                  ]
                }
              },
              "time_series": 1
            }
          }
        ]
    )
    

    上記のバージョン3.4以降のパイプラインを使用してこれを行うことができます。パイプラインでは、 $ addFields パイプラインステージ。演算子を使用して「time_series」の要素インデックスの配列を追加してドキュメントを作成します。また、時系列配列を逆にして、それぞれ $ range および $ reverseArray 演算子

    p の位置にある要素のため、ここで配列を逆にしました 配列内のは、常に位置 p + 1の要素よりも大きくなります つまり、 [p]-[p + 1] <0 また、 $ multiplyは使用しません。 ここに(バージョン3.2のパイプラインを参照)

    次に、 $ zipped インデックス配列を使用し、減算 $ mapを使用した結果の配列への式 オペレーター。

    次に、 $ sense null / Noneを破棄する結果 配列からの値と結果を元に戻しました。

    3.2では、 $ unwindを使用できます。 巻き戻す演算子 $ で始まる従来の「パス」の代わりに、オペランドとしてドキュメントを指定することにより、配列に各要素のインデックスを含めます。 。

    次のパイプラインでは、 $ group > ドキュメントを使用して、 $ pushを使用します 次のようなサブドキュメントの配列を返すアキュムレータ演算子:

    {
        "_id" : ObjectId("57c11ddbe860bd0b5df6bc64"),
        "time_series" : [
            { "value" : 10, "index" : NumberLong(0) },
            { "value" : 20, "index" : NumberLong(1) },
            { "value" : 40, "index" : NumberLong(2) },
            { "value" : 70, "index" : NumberLong(3) },
            { "value" : 110, "index" : NumberLong(4) }
        ]
    }
    

    最後に、 $ projectが登場します。 ステージ。この段階では、 $map $ groupで新しく計算された配列の各要素に一連の式を適用する演算子 ステージ。

    これが$map内で起こっていることです ( $ mapを参照してください forループとして) in 式:

    サブドキュメントごとに、を割り当てます。 $ letを使用して変数にフィールドを設定します 変数演算子。次に、配列内の次の要素の「value」フィールドの値からその値を減算します。

    配列の次の要素は現在のインデックスに1を加えた要素であるため、必要なのは $ arrayElemAt 演算子と単純な $ add 現在の要素のインデックスと1の位置 。

    $ extract 式は負の値を返すため、値に -1を掛ける必要があります $ multiplyを使用する オペレーター。

    また、 $ filter も必要です。 最後の要素がNoneであるため、結果の配列 またはnull 。その理由は、現在の要素が最後の要素である場合、 $ extract Noneを返します 次の要素のインデックスが配列のサイズに等しいためです。

    db.collection.aggregate([
      {
        "$unwind": {
          "path": "$time_series",
          "includeArrayIndex": "index"
        }
      },
      {
        "$group": {
          "_id": "$_id",
          "time_series": {
            "$push": {
              "value": "$time_series",
              "index": "$index"
            }
          }
        }
      },
      {
        "$project": {
          "time_series": {
            "$filter": {
              "input": {
                "$map": {
                  "input": "$time_series",
                  "as": "el",
                  "in": {
                    "$multiply": [
                      {
                        "$subtract": [
                          "$$el.value",
                          {
                            "$let": {
                              "vars": {
                                "nextElement": {
                                  "$arrayElemAt": [
                                    "$time_series",
                                    {
                                      "$add": [
                                        "$$el.index",
                                        1
                                      ]
                                    }
                                  ]
                                }
                              },
                              "in": "$$nextElement.value"
                            }
                          }
                        ]
                      },
                      -1
                    ]
                  }
                }
              },
              "as": "item",
              "cond": {
                "$gte": [
                  "$$item",
                  0
                ]
              }
            }
          }
        }
      }
    ])
    

    効率が悪いと思うもう1つのオプションは、 map_reduce メソッド。

    >>> import pymongo
    >>> from bson.code import Code
    >>> client = pymongo.MongoClient()
    >>> db = client.test
    >>> collection = db.collection
    >>> mapper = Code("""
    ...               function() {
    ...                 var derivatives = [];
    ...                 for (var index=1; index<this.time_series.length; index++) {
    ...                   derivatives.push(this.time_series[index] - this.time_series[index-1]);
    ...                 }
    ...                 emit(this._id, derivatives);
    ...               }
    ...               """)
    >>> reducer = Code("""
    ...                function(key, value) {}
    ...                """)
    >>> for res in collection.map_reduce(mapper, reducer, out={'inline': 1})['results']:
    ...     print(res)  # or do something with the document.
    ... 
    {'value': [10.0, 20.0, 30.0, 40.0], '_id': ObjectId('57c11ddbe860bd0b5df6bc64')}
    

    すべてのドキュメントを取得して、 numpy.diffを使用することもできます このように導関数を返すには:

    import numpy as np
    
    
    for document in collection.find({}, {'time_series': 1}):
        result = np.diff(document['time_series']) 
    


    1. 列挙型のマングースモデルのカスタムエラーメッセージ

    2. MongoDBシェルで実行中のクエリを中止するにはどうすればよいですか?

    3. phpとmongodbでのこれまでのタイムスタンプ

    4. MongoDBは一度に複数のコレクションをクエリします