7

This answer clearly shows some examples of proto text parsing, but does not have an example for maps.

If a proto has:

map<int32, string> aToB

I would guess something like:

aToB {
    123: "foo"
}

but it does not work. Does anyone know the exact syntax?

Community
  • 1
  • 1
lf215
  • 1,185
  • 7
  • 41
  • 83

2 Answers2

6

I initially tried extrapolating from an earlier answer, which led me astray, because I incorrectly thought multiple k/v pairs would look like this:

aToB {         # (this example has a bug)
    key: 123
    value: "foo"
    key: 876        # WRONG!
    value: "bar"    # NOPE!
}

That led to the following error:

 libprotobuf ERROR: Non-repeated field "key" is specified multiple times.

Proper syntax for multiple key-value pairs:

(Note: I am using the "proto3" version of the protocol buffers language)

aToB {
    key: 123
    value: "foo"
}
aToB {
    key: 876        
    value: "bar"    
}

The pattern of repeating the name of the map variable makes more sense after re-reading this relevant portion of the proto3 Map documentation, which explains that maps are equivalent to defining your own "pair" message type and then marking it as "repeated".


A more complete example:

proto definition:

syntax = "proto3";
package myproject.testing;

message UserRecord {
  string handle = 10;
  bool paid_membership = 20;
}

message UserCollection {
  string description = 20;
  // HERE IS THE PROTOBUF MAP-TYPE FIELD:
  map<string, UserRecord> users = 10;
}

message TestData {
  UserCollection user_collection = 10;
}

text format ("pbtxt") in a config file:

user_collection {
  description = "my default users"
  users {
    key: "user_1234"
    value {
      handle: "winniepoo"
      paid_membership: true
    }
  }
  users {
    key: "user_9b27"
    value {
      handle: "smokeybear"
    }
  }
}

C++ that would generate the message content programmatically

myproject::testing::UserRecord user_1;
user_1.set_handle("winniepoo");
user_1.set_paid_membership(true);
myproject::testing::UserRecord user_2;
user_2.set_handle("smokeybear");
user_2.set_paid_membership(false);

using pair_type =
    google::protobuf::MapPair<std::string, myproject::testing::UserRecord>;

myproject::testing::TestData data;
data.mutable_user_collection()->mutable_users()->insert(
    pair_type(std::string("user_1234"), user_1));
data.mutable_user_collection()->mutable_users()->insert(
    pair_type(std::string("user_9b27"), user_2));
pestophagous
  • 4,069
  • 3
  • 33
  • 42
  • 1
    By the way, you can also group map fields like this: `field_name: [{key: 1, value: 2}, {key: 3, value: 4}, ...]`. – wvxvw May 16 '18 at 13:11
  • How would the decoding of this protobuf message with these map variable look like in c++ for consumer ? – Invictus Mar 24 '22 at 10:26
3

The text format is:

aToB {
    key: 123
    value: "foo"
}
lf215
  • 1,185
  • 7
  • 41
  • 83