MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Tính toán phái sinh bậc nhất với khung tổng hợp 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
        }
      }
    ]
)

Chúng ta có thể sử dụng đường dẫn ở trên trong phiên bản 3.4+ để thực hiện việc này. Trong đường dẫn này, chúng ta sử dụng $ addFields giai đoạn đường ống. toán tử để thêm mảng chỉ số phần tử của "time_series" để làm tài liệu, chúng tôi cũng đảo ngược mảng chuỗi thời gian và thêm nó vào tài liệu bằng cách sử dụng $range $ reverseArray toán tử

Chúng tôi đã đảo ngược mảng ở đây vì phần tử ở vị trí p trong mảng luôn lớn hơn phần tử ở vị trí p + 1 có nghĩa là [p] - [p + 1] <0 và chúng tôi không muốn sử dụng $ nhân tại đây. (xem đường dẫn cho phiên bản 3.2)

Tiếp theo, chúng ta $ zipped dữ liệu chuỗi thời gian với mảng chỉ mục và áp dụng subract biểu thức cho mảng được kết quả bằng cách sử dụng $ map nhà điều hành.

Sau đó, chúng tôi $ slice kết quả để loại bỏ null / None giá trị từ mảng và đảo ngược lại kết quả.

Trong 3.2, chúng ta có thể sử dụng $ unwind toán tử để thư giãn mảng của chúng tôi và bao gồm chỉ mục của từng phần tử trong mảng bằng cách chỉ định tài liệu làm toán hạng thay vì "đường dẫn" truyền thống có tiền tố là $ .

Tiếp theo trong quy trình, chúng ta cần $ group tài liệu của chúng tôi và sử dụng $ push toán tử tích lũy để trả về một mảng tài liệu con giống như sau:

{
    "_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) }
    ]
}

Cuối cùng là $ project sân khấu. Trong giai đoạn này, chúng ta cần sử dụng $ map toán tử để áp dụng một chuỗi biểu thức cho từng phần tử trong mảng mới được tính trong $ group sân khấu.

Đây là những gì đang diễn ra bên trong $ map (xem $ map như một vòng lặp for) in biểu thức:

Đối với mỗi tài liệu con, chúng tôi chỉ định giá trị vào một biến bằng cách sử dụng $ let toán tử biến. Sau đó, chúng tôi trừ giá trị của nó khỏi giá trị của trường "giá trị" của phần tử tiếp theo trong mảng.

Vì phần tử tiếp theo trong mảng là phần tử ở chỉ mục hiện tại cộng với một phần tử, tất cả những gì chúng ta cần là sự trợ giúp của $ arrayElemAt toán tử và một $ add đơn giản ý chỉ chỉ mục của phần tử hiện tại và 1 .

$ subtract biểu thức trả về giá trị âm vì vậy chúng ta cần nhân giá trị với -1 bằng cách sử dụng $ nhân nhà điều hành.

Chúng tôi cũng cần $ filter mảng được kết quả vì nó là phần tử cuối cùng Không có hoặc null . Lý do là khi phần tử hiện tại là phần tử cuối cùng, $ subtract return Không vì chỉ số của phần tử tiếp theo bằng kích thước của mảng.

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
            ]
          }
        }
      }
    }
  }
])

Một tùy chọn khác mà tôi nghĩ là kém hiệu quả hơn là thực hiện thao tác bản đồ / thu nhỏ trên bộ sưu tập của chúng tôi bằng cách sử dụng map_reduce phương pháp.

>>> 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')}

Bạn cũng có thể truy xuất tất cả tài liệu và sử dụng numpy.diff để trả về dẫn xuất như sau:

import numpy as np


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


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mongodb đứng ở đâu trong định lý CAP?

  2. Làm cách nào để bạn thay đổi quyền của người dùng MongoDB?

  3. FindIterable <Document> có tải tất cả tài liệu không?

  4. Làm thế nào để kiểm tra xem mongo db có đang chạy trên Mac hay không?

  5. Làm thế nào để (đúng cách) Triển khai MongoDB trên Kubernetes và Truy cập nó từ một Pod / Job khác?