首页 > 解决方案 > 如何通过 REST 在 Firestore 文档中添加/删除数组元素?

问题描述

我想使用一个数组将来自 Arduino 的温度读数存储在 Firestore 数据库中。到目前为止,我(可能很糟糕)的思考方式是阅读文档,在 Arduino 上执行我的数组操作,然后将整个数组发送回 Firestore。我根本不知道如何通过 REST 写入 Firestore,所以我还没有实现它。这是我的代码:

void writeTemp(String url, int temperature) {
    // writeTemp() appends the given temperature to an array. temperature[0]
    // holds the oldest temperature while temperature[9] holds the first.
    // When a new temperature is put in, the last one is taken out.
    HTTPClient http;

    http.begin(url);
    int httpCode = http.GET();

    // Gets the current temperature array from the provided URL.
    String payload = http.getString();
    Serial.println(httpCode);  // Prints HTTP response code.

    // Calculates the size of the JSON buffer. This is big enough for 11
    // temperature values that are all 3 digits so as long as you're not using
    // this on the Sun you're probably fine.
    const size_t capacity = JSON_ARRAY_SIZE(11) + 14 * JSON_OBJECT_SIZE(1) +
                            JSON_OBJECT_SIZE(4) + 440;

    DynamicJsonDocument doc(capacity);  // Makes the JSON document
    DeserializationError err = deserializeJson(doc, payload);

    // Prints out the deserialization error if an error occurred
    if (err) {
        Serial.print("JSON DESERIALIZE ERROR: ");
        Serial.println(err.c_str());
    }

    // Sets up the array from the JSON
    JsonArray temperatureArray =
        doc["fields"]["Temperature"]["arrayValue"]["values"];

    // Creates a new array object to store the new temperature
    JsonObject newTemp = temperatureArray.createNestedObject();

    // Puts the new temperature in the new array object. For some reason,
    // Firestore stores numbers as strings so the temperature is converted into
    // a string.
    newTemp["integerValue"] = String(temperature);

    // Removes the first (oldest) array object.
    temperatureArray.remove(0);

    // Removes irrelevant data that we got from the Firestore request
    doc.remove("name");
    doc.remove("createTime");
    doc.remove("updateTime");

    String newJson;
    serializeJson(doc, newJson);
    Serial.println(newJson);
}

我如何将这个新的 JSON 发送回 Firestore?我这样做对吗?我听说过交易,这听起来像是理论上更好的方法来做我想做的事情,但我找不到任何关于如何做的指南或可读文档。我的数据库现在处于测试模式,因此无需担心身份验证。

火场布局

标签: firebaserestarduinogoogle-cloud-firestore

解决方案


Firestore REST API 的文档在此处

要创建文档,您需要向具有以下格式的 URL 发出 POST 请求:

https://firestore.googleapis.com/v1/{parent=projects/*/databases/*/documents/**}/{collectionId}

Document在请求正文中有一个 a 的实例。


更具体地说,下面是一个简单 HTML 页面中的示例(使用Axios库发出 HTTP 请求)。collection1此代码将在Firestore 集合中创建一个新文档。

只需将此文件保存在本地磁盘上,调整值<yourprojectID>并在浏览器中直接从本地磁盘打开此页面。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  </head>

  <body>
    <script>
      var firebaseProjectId = '<yourprojectID>';

      var collectionId = 'collection1';

      var url =
        'https://firestore.googleapis.com/v1/projects/' +
        firebaseProjectId +
        '/databases/(default)/documents/' +
        collectionId;

      var writeObj = {
        fields: {
          name: {
            stringValue: 'theName'
          },
          initialBudget: {
            doubleValue: 1200
          }
        }
      };

      axios.post(url, writeObj).catch(function(error) {
        console.log(error);
      });
    </script>
  </body>
</html>

为了更新现有文档中的数组,您必须使用FieldTransformwithappendMissingElements元素。

此文档关于appendMissingElements元素的摘录:

appendMissingElements:如果给定的元素尚未出现在当前字段值中,则按顺序附加它们。如果该字段不是数组,或者该字段尚不存在,则首先将其设置为空数组。

FieldTransform您将在下面找到包含appendMissingElements元素的值示例。

    {
           "transform": {
            "document": "projects/" + firebaseProjectId + "/databases/(default)/documents/....,
            "fieldTransforms": [
             {
              "setToServerValue": "REQUEST_TIME",
              "fieldPath": "lastUpdate"
             },
             {
              "appendMissingElements": {
               "values": [
                {
                 "stringValue": "...."
                }
               ]
              },
              "fieldPath": "fieldName"
             }
            ]
           }
      }

根据您的评论更新

以下应该有效(经过积极测试):

  var collectionId = 'SensorData';

  var url =
    'https://firestore.googleapis.com/v1/projects/' +
    firebaseProjectId +
    '/databases/(default)/documents:commit';

  var writeObj = {
    writes: {
      transform: {
        document:
          'projects/' +
          firebaseProjectId +
          '/databases/(default)/documents/' +
          collectionId +
          '/Temperature',
        fieldTransforms: [
          {
            setToServerValue: 'REQUEST_TIME',
            fieldPath: 'lastUpdate'
          },
          {
            appendMissingElements: {
              values: [
                {
                  integerValue: 25
                }
              ]
            },
            fieldPath: 'Temperature'
          }
        ]
      }
    }
  };

推荐阅读