bblanchon / ArduinoJson

📟 JSON library for Arduino and embedded C++. Simple and efficient.
https://arduinojson.org
MIT License
6.63k stars 1.1k forks source link

Going crazy trying to check if a key exists! #2070

Closed IAmOrion closed 3 months ago

IAmOrion commented 3 months ago

Hoping someone can tell me what I'm doing wrong - new to using ArduinoJSON and going crazy trying to figure out how to check if a key exists!!

Here's my simplified relevant code

void loop() {
  uint32_t meterID = 1234567890;
  uint32_t meterID2 = 0987654321;

  char _meterID[16];
  char _meterID2[16];

  sprintf(_meterID,"%lu", meterID);
  sprintf(_meterID2,"%lu", meterID2);

  Serial.print("JT1: "); Serial.println(_meterID);
  JsonObject myArrayCheck = doc.to<JsonObject>();
  const char* checkONE = myArrayCheck[_meterID]["variable1"];
  hasMeterID = myArrayCheck.containsKey(_meterID)["variable1"];
  Serial.print("JT1 CheckONE: "); Serial.println(checkONE);
  Serial.print("JT1 hasMeterID: "); Serial.println(hasMeterID);

  // no data in json array so any key exist check should return false, nothing found

  JsonArray myArray = doc[_meterID].to<JsonArray>();
  myArray[0]["variable1"] = "content1";
  myArray[0]["variable2"] = "content2";
  myArray[0]["variable3"] = "content3";
  myArray[0]["variable4"] = "content4";
  myArray[0]["variable5"] = "content5";

  myArray = doc[_meterID2].to<JsonArray>();
  myArray[0]["variable1"] = "content1";
  myArray[0]["variable2"] = "content2";
  myArray[0]["variable3"] = "content3";
  myArray[0]["variable4"] = "content4";
  myArray[0]["variable5"] = "content5";

  doc.shrinkToFit();  // optional

  serializeJsonPretty(doc, Serial);

  delay(1000);

  Serial.println();
  Serial.print("JT2: "); Serial.println(_meterID);
  JsonObject myArrayCheckTWO = doc.to<JsonObject>();
  const char* checkTWO = myArrayCheckTWO[_meterID]["variable1"]; // <-- this is empty/null
  hasMeterID = myArrayCheckTWO.containsKey(_meterID)["variable1"]; // <-- this does return true but docs say avoid plus I think it's not working correctly and just returning true even when false
  Serial.print("JT2 checkTWO: "); Serial.println(checkTWO);
  Serial.print("JT2 hasMeterID: "); Serial.println(hasMeterID);

  // json array now contains data, and I would expect it to find the key but it's always false!

  while(1);
}

Here's the generated JSON:

{
  "1234567890": [
    {
      "variable1": "content1",
      "variable2": "content2",
      "variable3": "content3",
      "variable4": "content4",
      "variable5": "content5"
    }
  ],
  "0987654321": [
    {
      "variable1": "content1",
      "variable2": "content2",
      "variable3": "content3",
      "variable4": "content4",
      "variable5": "content5"
    }
  ]
}

I've spent a good few hours trying all manor of different check and suspect I'm overthinking it or missing something obvious that will make me feel super dumb once realised!

For my use case, I simply need to check if key "1234567890" exists

Many thanks in advance

IAmOrion commented 3 months ago

I managed eventually to resolve this (may or may not be "best practise") by simply doing:

const char* meter_serial_number = doc[_meterID][0]["variable1"];
bblanchon commented 3 months ago

Hi @IAmOrion,

Yes, this corresponds to the library's best practices.

You seemed upset in your initial message. I'm assuming this was due to a problem in ArduinoJson's documentation or tooling. Please let me know if there is anything I can do to improve them.

Best regards, Benoit

IAmOrion commented 3 months ago

Hi @IAmOrion,

Yes, this corresponds to the library's best practices.

You seemed upset in your initial message. I'm assuming this was due to a problem in ArduinoJson's documentation or tooling. Please let me know if there is anything I can do to improve them.

Best regards, Benoit

Hi @bblanchon

Not upset as such, I was frustrated at not getting it to work.

To summarise the docs https://arduinojson.org/v7/api/jsonvariant/containskey/

JsonDocument doc;
JsonVariant root = doc.to<JsonVariant>();
...
const char* error = root["error"];
if (error) {
  Serial.println(error);
  return;
}

or https://arduinojson.org/v7/api/jsonobject/containskey/

JsonDocument doc;
JsonObject root = doc.to<JsonObject>();

const char* error = root["error"];
if (error) {
  Serial.println(error);
  return;
}

did not work for me.

Specifically,

JsonObject root = doc.to<JsonObject>();
const char* error = root["error"];

eventually seemed to be not needed when I could directly access doc[]

So in my case

JsonDocument doc;
JsonObject root = doc.to<JsonObject>();

const char* error = root[_meterID][0]["variable1"];
if (error) {
  Serial.println(error);
  return;
}

Never worked. I tried variations too like:

const char* error = root[_meterID]["variable1"];
const char* error = root[_meterID][0]["variable1"][0];
const char* error = root[0][_meterID][0]["variable1"][0];

But these also never worked.

I ultimately skipped the JsonObject root = doc.to<JsonObject>(); part and just used the following

const char* meter_serial_number = doc[_meterID][0]["variable1"];

which rendered the inital part of the docs example not needed. Either that, or the example just confused me resulting in me misunderstanding

Hope that all makes sense :)

bblanchon commented 3 months ago

Thank you for the feedback, @IAmOrion. Indeed people often confuse JsonDocument::to<T>() with JsonDocument::as<T>(); I shouldn't have used it here. I updated the examples so they don't rely on JsonDocument::to<T>(). Let me know if this still needs improvement.

IAmOrion commented 3 months ago
Screenshot 2024-03-18 at 16 10 16

If I was to give some critical feedback I'd say these need fixing too... in my personal opinion they would be better suited as self contained examples so to so speak, because now you've removed the JsonObject root = doc.to<JsonObject>(); part there's no obvious link to what "root" even is here: const char* error = root["error"];

As an example - to me this is a standalone working example

Screenshot 2024-03-18 at 16 19 13

Hopefully that makes sense.

Great work on this library btw, I appreciate you taking the time to see where you can improve and adapt things if needed

bblanchon commented 3 months ago

Thank you again for the feedback. I updated the pages according to your suggestion. Let me know if you find other confusing things on the site.