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

Posted

技术标签:

【中文标题】使用 Cloudant 从 JSON 数组中检索 JSON 对象【英文标题】:Retrieve a JSON object from JSON array using Cloudant 【发布时间】:2018-11-29 13:56:25 【问题描述】:

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

下面,我将更详细地解释我的问题: 将 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 个城市,因此 payload 数组中有 1600 个嵌套对象)。此外,在提到的 1600 个对象中,其他数组和对象再次嵌套在其中。对于payload 数组中的所有对象,第一个字段是cityName

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

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

我必须指定一个开始 时间戳(或id)和一个结束 时间戳,从而只生成此间隔内的JSON 文档。 此外,我需要在 JSON 文档中通过 cityName 仅指定一个或多个特定城市(有 1600 个城市),然后获取可用汽车的数量 availableCarsoccupiedCars 的数量城市。

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


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

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

谁能帮我定义一个查询和索引以获得上述结果?我可以使用 cloudant 查询来做到这一点吗?

【问题讨论】:

您是要查询namelicensestate,还是要查询namestate 并让它返回license @HypnicJerk 我更改了上面的文本和示例 JSON 文档;试图让我的问题更容易理解。因此,您在评论中引用的字段 namelicense 不再存在。 【参考方案1】:

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

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

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

经验法则:小文件。在可能的情况下,不可变模型。文档将更改或作为一个单元访问的数据分组。

【讨论】:

感谢您的回答。我只想将 JSON 响应“按原样”保存在数据库中,以便稍后分析/解释它们。然而,正如你所说,我同意我现在对 cloudant 有了更好的理解,这肯定不是一个理想的数据结构。感谢您的明确解释。

以上是关于使用 Cloudant 从 JSON 数组中检索 JSON 对象的主要内容,如果未能解决你的问题,请参考以下文章

使用jackson从json数组中检索一个值

Laravel 5:从 $request 中检索 JSON 数组

使用swiftyjson从索引对象数组ios中检索json的标题

IBM Cloud Functions Service 在尝试创建与 Cloudant 操作的新绑定时无法检索数据库列表

如何使用 Retrofit 从 Json 数组列表中检索 MpAndroid 图表内的数据?

在 Cloudant 中使用 MapReduce 获取地理空间索引的结果