使用 Cloudant 从 JSON 数组中检索 JSON 对象

Retrieve a JSON object from JSON array using Cloudant

我每 40 分钟执行一次 API 调用,以检索车队中每辆车的当前状态信息。并且每次调用都会将一个新的 JSON 文档添加到 Cloudant 数据库中。每个 JSON 文件都定义了在许多城市的许多地点的每辆汽车的当前可用性状态。数据库中目前大约有 2200 JSON 个文档。所有 JSON 文档都有一个名为 payload 的字段,其中包含所有信息;它是一大堆对象。我不想检索整个 payload 对象数组,而是想通过查询检索 所需的信息(因此,只有该数组的一个或多个对象)。但是,我很难起草仅产生所需数据的查询。

下面,我将更详细地解释我的问题: 将 JSON 文档保存到 Cloudant 时,文档中定义了一个 timestamp_id 参数定义为等于此时间戳。下面,我展示了这些 JSON 文档的简化版本:

 {
  "_id": "1540914946026",
  "_rev": "3-c1834c8a230cf772e41bbcb9cf6b682e",
  "timestamp": 1540914946026,
  "datetime": "2018-10-30 15:55:46",
  "payload": [
    {
      "cityName": "Abcoude",
      "locations": [
        {
          "address": "asterlaan 28",
          "geoPoint": {
            "latitude": 52.27312,
            "longitude": 4.96768
          },
          "cars": [
            {
              "mod": "BMW",
              "state": "FREE"
            }
          ]
        }
      ],
      "availableCars": 1,
      "occupiedCars": 0
    },
    {
      "cityName": "Alkmaar",
      "locations": [
        {
          "address": "Aert de Gelderlaan 14",
          "geoPoint": {
            "latitude": 52.63131,
            "longitude": 4.72329
          },
          "cars": [
            {
              "model": "Volswagen",
              "state": "FREE"
            }
          ]
        },
        {
          "address": "Ardennenstraat 49",
          "geoPoint": {
            "latitude": 52.66721,
            "longitude": 4.76046
          },
          "cars": [
            {
              "mod": "BMW",
              "state": "FREE"
            }
          ]
        },
        {
          "address": "Beneluxplein 7",
          "geoPoint": {
            "latitude": 52.65356,
            "longitude": 4.75817
          },
          "cars": [
            {
              "mod": "BMW",
              "state": "FREE"
            }
          ]
        },
        {
          "address": "Dr. Schaepmankade 1",
          "geoPoint": {
            "latitude": 52.62595,
            "longitude": 4.75122
          },
          "cars": [
            {
              "mod": "BMW",
              "state": "OCCUPIED"
            }
          ]
        },
        {
          "address": "Kennemerstraatweg",
          "geoPoint": {
            "latitude": 52.62909,
            "longitude": 4.74226
          },
          "cars": [
            {
              "model": "Mercedes",
              "state": "FREE"
            }
          ]
        },
        {
          "address": "NS Station Alkmaar Noord/Parkeerterrein Noord",
          "geoPoint": {
            "latitude": 52.64366,
            "longitude": 4.7627
          },
          "cars": [
            {
              "model": "Tesla",
              "state": "FREE"
            }
          ]
        },
        {
          "address": "NS Station Alkmaar/Stationsweg 56",
          "geoPoint": {
            "latitude": 52.6371,
            "longitude": 4.73935
          },
          "cars": [
            {
              "model": "Tesla",
              "state": "FREE"
            }
          ]
        },
        {
          "address": "Oude Hoeverweg",
          "geoPoint": {
            "latitude": 52.63943,
            "longitude": 4.72928
          },
          "cars": [
            {
              "model": "Tesla",
              "state": "FREE"
            }
          ]
        },
        {
          "address": "Parkeerterrein Wortelsteeg",
          "geoPoint": {
            "latitude": 52.63048,
            "longitude": 4.75487
          },
          "cars": [
            {
              "model": "Tesla",
              "state": "OCCUPIED"
            }
          ]
        },
        {
          "address": "Schoklandstraat 38",
          "geoPoint": {
            "latitude": 52.65812,
            "longitude": 4.75359
          },
          "cars": [
            {
              "model": "Volkswagen",
              "state": "FREE"
            }
          ]
        }
      ],
      "availableCars": 8,
      "occupiedCars": 2
    }
  ]
}

如您所见,payload 字段是一个包含多个对象的数组(仅供参考:此数组中的每个对象代表一个特定城市:有 1600 个城市,因此 [= 中有 1600 个嵌套对象14=]数组)。此外,在提到的 1600 个对象中的每一个中,其他数组和对象也嵌套在其中。对于 payload 数组中的所有对象,第一个字段是 cityName

此外,还有一个嵌套数组locations(在payload数组的1600个对象中的每个对象中)表示特定城市中的所有地址。 locations 数组的大小可以是 1 到 600,这意味着每个城市有 1 到 600 个嵌套对象/地址。 payload 数组的所有对象中的最后两个字段是 availableCarsoccupiedCars.

我想要查询文档以查看在特定时间间隔内特定城市有多少可用和占用的汽车。为此:

例如,在这个简化的例子中,我想查询阿尔克马尔市从 1540914946026(纪元时间)到现在的状态信息(availableCars & `occupiedCars)。我想得到以下结果:

{
 "id":"1540914946026",
 "cityName":"Alkmaar",
 "availableCars":8,
 "occupiedCars":2
 }

这只是一个例子,实际上,我希望能够查询其他城市,或者同时查询几个城市,然后为每个城市获取可用汽车的数量availableCars和占用车数occupiedCars.

谁能帮我定义一个查询和索引来得到上面的结果?我可以使用 cloudant 查询来执行此操作吗?

您的数据模型没有发挥 Cloudant 的优势。让每个文档将变化和访问的数据分组在一起。您的有效负载数组中的项目将更好地存储为离散文档。

如果您发现自己为了数据子集而进入文档中不断增长的数组,这是一个警告信号,表明您的数据模型不理想:文档现在是可变的并且不断增长(因此可能会发生更新冲突),随着时间的推移,访问变得越来越麻烦,因为 Cloudant 没有仅检索文档部分的机制。此外,Cloudant 对文档大小有限制 (1M),因此如果使用您建议的模型,您也可能会达到该限制,并且您的应用程序将停止工作。

话虽如此,可以创建一个视图索引,让您发出有效载荷的每个组件,这样您就可以按城市查找数据——但该解决方案仍然受到上述所有限制(文档模型是可变的,文档变大等)。

经验法则:小文档。不可变模型,如果可能的话。记录更改或作为一个单元访问的数据组。