How to attach arbitrary key-value metadata to node or edge

Is there any way I can attach metadata to a node or edge?

A simple key-value store (akin to Go maps) would do just fine.

My wild guess it’s not possible as I could not find map/hash in the type system, but I’m wondering maybe I missed something.

I understand Edges have facets and that’s nice but they don’t quite tick the box for arbitrary data (I’d be happy with some size limit imposed on the metadata)

Can you elaborate on your experience with facets? They are the only thing close to the idea of “Metadata”. There is no other. If I understand what is happening to your use case. I could guide you.

I asked this question almost a year ago when I played with Dgraph for the first time and never revised it because work and life happened, but now I’m diving back to it for a small project of mine and I’m feeling the need for this again.

I think this feature could be very beneficial not only for my use case but probably for many other people. Unless there is some way of already doing this, which I couldn’t find anywhere in the docs.

Basically, being able to attach arbitrary k/v pairs to Entities stored in Dgraph would make it much closer to property-ish graph DB. You could query for those attributes i.e. query for Node with attributes x, y, z. Now, some entities of the same Dgraph type in this “messy” world might contain some attributes and miss others etc.

Currently, if you want to attach some “metadata” to Entities or Edges you need to use facets. Which are fantastic, indeed, but say you are using Go (I can’t speak for other languages here I’m afraid), you need to explicitly define those facets as Fields in your Entity type structs one by one, but what if you don’t know in advance what sorts of attributes/facets you want to attach to entities/edges? As I said sometimes your node might have facets x, y and other times it might have y, z.

name: string @index(exact) .
attributes: kv .

type Foo {

If dgraph type system provided something like property / attributes type (even with limited number of k/v pairs) that would be fantastic. In you Go struct type you could simply do something like this:

type Foo struct {
  Name string `....`
  Attributes `json:"attributes,omitempty"`

On the 2021 roadmap is an item that might interest you: Support for JSON blob (as a predicate type). With that you can store whatever you want in one predicate, with some level of validation.

Attaching metadata to a node is already possible and is actual very native Dgraph. You don’t have to have a predefined schema for predicate.

As for adding meta data to an edge, I believe the solution is to create a linking node to hold the meta data. If you are early in your development, this may be feasible. This may have unintended side effects, but this would best align with Dgraph’s data structure in the SPO model. In case you didn’t know, part of Dgraph is actually a key-value store so this topic asking for key-value store support is kind of funny.

I’m not following you. Arbitrary how? Dgraph is “property-ish” per se. The pattern P -> O is Key value in practice. Your entity can have as many “KV” as you want. When do you say “arbitrary” are you saying something related to the Value type? as the value types in a predicate are fixed. Dgraph cannot handle multiple types of values in a single predicate. It is not viable.

Do you have any examples?

That is something related to Go. So, in Go is mandatory to insert the values in the structs? There’s no “optional” notation in Go struct? As for example in TypeScript interfaces you can have a gigantic “TS struct” and set all of it as optional.

But maybe I didn’t get your issue.

This is true, but querying it is not quite what I’m looking for in here. Unless we are talking about different things, in which case would you mind elaborate? I might be missing something.

For example I know I can store X in Dgraph and dont have to explicitly define predicate; however querying for those fields using DQL is not ideal; for example expand(_all_) does not return non-predicate fields, right?

You are right @MichelDiz (also, happy birthday!) I drowned myself in “technicalities” here – that’s not the hill I wanna die on :slight_smile:

A classic example in my case is when you are “building” nodes “dynamically” (say from an unprocessed text etc.) and discover uncommon properties that might be present in some nodes of the same type and not in others. These properties might not be clearly defined at the beginning of the task. Sometimes you just want to store an extra hint of data for further processing which does not quite fit into the model.

You can make struct properties optional by turning them into pointers and tagging them with omitempty, but that does not cover what I’m advocating here for. As I said what I have in mind are arbitrary properties discovered dynamically. I would not want to define ginormous Go types (models) to cover every single possibility out there. Ideally what you can do is what I mentioned: have a map[string]string or map[string]interface{} that can cover this model enriching metadata.

The JSON blob scalar proposal looks good for this use-case, actually. I’d just have to serialise the “metadata” into JSON but that’s almost non-issue. I think that will do just fine, actually.

1 Like

That is correct, the expand(_all_) utilizes the type system to know what predicates to ask for. If you did not need to expand all, then this should still work, but that is not your exact use case.

I agree! I have several use cases for this JSON blob scalar, mainly storing an ordered list, but also useful for storing adhoc data in key-value form like you suggested and query it with GraphQL still (returning the whole blob). I have some other thoughts on ways to improve this, but that would require JSON functions like MySQL has, and would complicate the original idea, let’s just push for this to be implemented first in a basic way and then we can make feature requests to make it even better :wink: