草庐IT

php - 如何使用 DynamoDB PHP 从表中获取最新的时间戳值

coder 2024-04-27 原文

我是 DynamoDB 的新手。
在我的应用程序中,每个注册用户的帐户上都有一些传感器,这些传感器每 5 分钟就会向我们的数据库发送一些数据。

现在我想显示“如果用户已登录到他的帐户,我应该需要显示他的所有传感器以及每个传感器的最新时间戳值”。

我通过三个查询来完成此操作,例如“我获取了他帐户下的所有设备 -> 原始传感器 ID -> 每个传感器的最新值”,因此执行此过程需要很长时间。

我的表格是这样的:

用户:

---------------------
|sno  | userId      |
---------------------
| 1   | naveenkumar |
|--------------------
| 2   | abc         |
|--------------------
| 3   | xyz         |
|--------------------

传感器设备:

---------------------
| id | sensorId     |
---------------------
| 1  | sensor1      |
|--------------------
| 2  | sensor2      |
|--------------------
| 3  | sensor3      |
|--------------------
| 4  | sensor4      |
---------------------
| 5  | sensor5      |
---------------------

用户传感器:

----------------------
| userId | sensorId  |
----------------------
| 1      |  1        |
|---------------------
| 1      |  2        |
|---------------------
| 1      |  4        |
|---------------------
| 2      |  5        |
|---------------------

数据表:

---------------------------------------------
| sensorId  | value    | timestamp          |
---------------------------------------------
| sensor1   | 4.3      | 2014-01-21 11:21:00|
|--------------------------------------------
| sensor2   | 5.0      | 2014-01-21 11:22:00|
|--------------------------------------------
| sensor3   | 10.0     | 2014-01-21 11:19:00|
|--------------------------------------------
| sensor4   | 6.3      | 2014-01-21 11:25:00|
|--------------------------------------------
| sensor1   | 8.3      | 2014-01-21 11:26:00|
|--------------------------------------------
| sensor2   | 6.0      | 2014-01-21 11:27:00|
|--------------------------------------------
| sensor3   | 9.0      | 2014-01-21 11:24:00|
|--------------------------------------------
| sensor4   | 6.3      | 2014-01-21 11:30:00|
|--------------------------------------------

最终输出表将在他的主页上看到用户:

---------------------------------------------
| sensorId  | value    | timestamp          |
---------------------------------------------
| sensor1   | 8.3      | 2014-01-21 11:26:00|
|--------------------------------------------
| sensor2   | 6.0      | 2014-01-21 11:27:00|
|--------------------------------------------
| sensor4   | 6.3      | 2014-01-21 11:30:00|
|--------------------------------------------

我的查询看起来像这样,执行起来需要很长时间,所以请为我提供更好的解决方案:

让我们假设 $_SESSION['login_id'] = 1;

<?php
  $aws = Aws::factory('config.php');
  $client = $aws->get("dynamodb");

  $tableName = "data_tbl";
  echo "<table border=1>";
  echo "<tr>";

  echo "<th>Sensor ID</th>";
  echo "<th>value</th>";
  echo "<th>Timestamp</th>";
  echo "</tr>";

  //Query to get user devices
  $devices = $client->query(array(
    "TableName" => "users-sensors",
    "KeyConditions" => array(
      "userId" => array(
        "ComparisonOperator" => ComparisonOperator::EQ,
        "AttributeValueList" => array(
          array(Type::STRING => $_SESSION['login_id'])
        )
      )
    )
  ));
  foreach ($devices['Items'] AS $key=>$value) {
    $id = $value['sensorId']['S'];
    //Query to get original sensorId from sensor serial number
    $device = $client->query(array(
      "TableName" => "sensor_devices",
      "KeyConditions" => array(
        "id" => array(
          "ComparisonOperator" => ComparisonOperator::EQ,
          "AttributeValueList" => array(
            array(Type::STRING => $id)
          )
        )
      )
    ));
    $dids =  $device['Items'][0]['sensorId'][Type::STRING];
    //Query to get all latest values of sensors
    $response = $client->query(array(
      "TableName" => $tableName,
      "KeyConditions" => array(
        "sensorId" => array(
          "ComparisonOperator" => ComparisonOperator::EQ,
          "AttributeValueList" => array(
            array(Type::STRING => $dids)
          )
        )
      ),
      "Select" => "SPECIFIC_ATTRIBUTES",
      "AttributesToGet" => array("sensorId","value","timestamp"),
      "ScanIndexForward" => false,
      "Limit" => 1  
    ));
    foreach ($response['Items'] AS $key=>$value) {
      echo "<tr>";
      $link = "graph.php?id=".$id;
      echo "<td><a href='$link'>".$value['sensorId']['S']."</a></td>";
      echo "<td><a href='$link'>".$value['value']['S']."</a></td>";
      $epoch = $value['timestamp']['S'];
      $timestamp = date('Y-m-d H:i:s', $epoch);
      echo "<td><a href='$link'>".$timestamp."</a></td>";
      echo "</tr>";
    }
  }
  echo "</table>";
?>

如果我能得到答案,我就能完成我的工作。 谢谢

最佳答案

您正在从关系数据库的角度看待和思考 DynamoDB。 DynamoDB 不是关系数据库。您(通常)不想像在 MySQL 中那样在 DynamoDB 中对数据建模。就像软件开发/计算机科学中的任何事情一样,这是一种权衡。您支付一些数据反规范化和复制成本,以换取极低的查询延迟和极强的可扩展性。

我不使用 PHP,所以我无法帮助您编写代码,但我想我可以帮助您设计数据模型。

如果我正确理解您的要求,则需要在用户登录时获取每个用户的传感器 ID 列表及其最新时间戳。如果是这样,您可以采用以下一种可能的方法将查询次数从 3 次减少到 1 次:

您表的哈希键是 UserID,范围键是传感器事件的 Timestamp:

------------------------
| Hash Key | Range Key |
------------------------
| User ID  | Timestamp |
------------------------

该表将具有 Sensor ID 属性,对应于观察到事件的传感器。传感器 29 于 2014 年 2 月 14 日上午 11:51 观察到的用户 12 的条目可能如下所示:

---------------------------------------
| Hash Key | Range Key     | Sensor ID |
----------------------------------------
|    12    | 1392396884000 |    29     |
----------------------------------------

请注意,我使用了以毫秒为单位的时间戳,以便 DynamoDB 可以轻松地对其进行排序。

现在,当用户登录时,您可以通过用户 ID 查询表以获取该用户的每个事件。在您的查询请求中,设置 ScanIndexForward => false(来自此处的 DynamoDBSDK 文档:http://docs.aws.amazon.com/aws-sdk-php/latest/class-Aws.DynamoDb.DynamoDbClient.html#_query)。 DynamoDB 将按从最近到最不最近的顺序返回您的结果。如果该用户有大量事件,DynamoDB 将相应地对结果集进行分页,但您可以在 DynamoDB 文档中了解如何处理。

现在您有了该用户的事件列表(或 PHP 中的任何相应数据结构)。您需要按 SensorID 进行过滤以获取最新的。好消息是,由于结果是有序的,您只需遍历结果并检查每个项目的 Sensor ID;如果您没有从该 Sensor ID 获得结果,请将其添加到您的过滤集合中。如果您已经从该 Sensor ID 添加了一个事件,则意味着您拥有来自该 Sensor ID 的该 User ID 的最新事件你应该跳过它。

根据您的应用程序的需要,如果您需要获取传感器的每个事件的列表,您可以简单地使用 Sensor ID 的索引散列键在表上放置一个全局二级索引> 和事件 Timestamp。由于 User ID 是表主键的一部分,DynamoDB 会自动将其投影到索引中。

希望对您有所帮助。

关于php - 如何使用 DynamoDB PHP 从表中获取最新的时间戳值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21250308/

有关php - 如何使用 DynamoDB PHP 从表中获取最新的时间戳值的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  4. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  5. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  6. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  10. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

随机推荐