Schema for maps of kv pairs with variant values

Hi, I am working with a fairly generic object/document type that has a map of KV pairs, where the value is an array of variants, and the type is specified in the variant itself. So, a single entry in the object/document could look something like this:

"content" = [{
          "key": "My Key",
          "value": [[
              "string",
              "my label string"
            ],[
              "asset",
              "701.92 USD"
            ],[
              "int64",
              8989832
            ]]
        }]

The first item in the array is the name of the data type, followed by the value. A single document is a list of these types of entries.

Is this something that can be modeled in dgraph?

I’ve been trying a number of different permutations for the Schema, with no luck. Is this possible with custom types? Any materials or example(s) for something like this?

thank you!

That model isn’t possible in Dgraph. But you can try list type with Facets. e.g

{
   "set": [
      {
         "key": "My Key",
         "value|name": {
            "0": "string",
            "1": "asset",
            "2": "int64"
         },
         "value": [
            "my label string",
            "701.92 USD",
            8989832
         ]
      }
   ]
}
{
  q(func: has(key)){
    key
    value @facets
  }
}

Response

{
  "data": {
    "q": [
      {
        "key": "My Key",
        "value|name": {
          "0": "asset",
          "1": "int64",
          "2": "string"
        },
        "value": [
          "701.92 USD",
          "8989832",
          "my label string"
        ]
      }
    ]
  }
}

Or you can use normal nodes, that can be more useful to apply filters and functions.

{
   "set": [
      {
         "key": "My Key",
         "valueV2": [
            {
               "string": "my label string"
            },
            {
               "asset": "701.92 USD"
            },
            {
               "int64": 8989832
            }
         ]
      }
   ]
}

Or like this

{
   "set": [
      {
         "key": "My Key",
         "valueV3": [
            {
               "KV": [
                  "string",
                  "my label string"
               ]
            },
            {
               "KV": [
                  "asset",
                  "701.92 USD"
               ]
            },
            {
               "KV": [
                  "int64",
                  "8989832"
               ]
            }
         ]
      }
   ]
}

But the order isn’t preserved. Cuz it is a list type.

To clarify, I think you meant ORDER isn’t preserved. I ran into that myself.

1 Like

Thanks for the reply. I think facets will work for this. Will that solution maintain the order? And will it support multiple values of the same type in the same list (appears so)? TBH, the types are not so important to save here if dgraph supports having strings and integers in the same list like your example. (it is just how the source system renders them)

Would it work (and maintain order) simply as this?

{
         "key": "My Key",
         "value": [
            "my label string",
            "701.92 USD",
            8989832
         ]
      }

Facets on List Type are “tangled”. They can change orders on the response, but they will have the same index always.

Nope. For that, you should use the second example.

List Type in general doesn’t maintain the order. As far as I know.

Check this https://dgraph.io/docs/mutations/json-mutation-format/#creating-a-list-with-json-and-interacting-with to see more about interacting with List Type.

Also to be aware of with lists, is that they work as a set. If you have two identical values in key value pairs and didn’t care about order, it might still produce the wrong results as

["my value","my value","1"]

would only get stored as

["my value","1"]
1 Like

Nice catch, I think this is important, would mind adding a note on the docs about this?

Hi, I’ve restructured my data quite a bit so that I believe it should be able to support both order and labels for content. However, I now receive the following error:

"Got unsupported type for list: content_groups"

Essentially, content_groups is a list of lists.

{
    "set": [
        {
            "certificates": [],
            "created_date": "2020-08-24T16:59:58.500",
            "hash": "363bccee26dd6ffaa8f107d8ceb6a666a34f1de978c57dcad487475d107b79e5",
            "creator": "johnnyhypha1",
            "content_groups": [
                [
                    {
                        "label": "content_group_name",
                        "value": [
                            "string",
                            "My content group #1"
                        ],
                        "sequence": 0
                    },
                    {
                        "label": "important_value",
                        "value": [
                            "int64",
                            42
                        ],
                        "sequence": 1
                    }
                ],
                [
                    {
                        "label": "",
                        "value": [
                            "string",
                            "My content group #2"
                        ],
                        "sequence": 0
                    }
                ]
            ]
        }
    ]
}

If I make content_groups a single list, it works, but my aim is to support it as a list of lists. Any advice for this? thanks

Lists (in this case Value List type) in Dgraph are similar to “sets” in JS. But it can’t hold arrays, objects and so on. Just the value as a list. And each value is unique.

Even for an edge, you can’t add it as arrays as you do in a JS Object for example. So your mutation should look like this:

It can’t be like { "content_groups": [ [ { .. } ], [ { .. }, { .. } ] ] }

have to be like
{ "content_groups": [ "edge": [ { .. } ], "edge": [ { .. }, { .. } ] ] }
Which in graph pattern means
content_groups => edge => Objects

{
   "set": [
      {
         "certificates": [],
         "created_date": "2020-08-24T16:59:58.500",
         "hash": "363bccee26dd6ffaa8f107d8ceb6a666a34f1de978c57dcad487475d107b79e5",
         "creator": "johnnyhypha1",
         "content_groups": [
            {
               "myValues": [
                  {
                     "label": "content_group_name",
                     "value": [
                        "string",
                        "My content group #1"
                     ],
                     "sequence": 0
                  },
                  {
                     "label": "important_value",
                     "value": [
                        "int64",
                        42
                     ],
                     "sequence": 1
                  }
               ]
            },
            {
               "myValues": [
                  {
                     "label": "",
                     "value": [
                        "string",
                        "My content group #2"
                     ],
                     "sequence": 0
                  }
               ]
            }
         ]
      }
   ]
}

You can think of it as an array of objects. And they have to have edges connecting them.

1 Like

If there was a way to store an ordered set, that would be a great feature.

I thought it was JSON that does not support order in arrays and not the db itself. But that does not appear to be the culprit:

Make a request tho :stuck_out_tongue:

1 Like