JSON format ... doesn't differentiate between INT/FLOAT

Moved from GitHub dgo/66

Posted by jvsteiner:

Since the mutation input is in JSON format which doesn’t differentiate between INT/FLOAT (everything is a number), the server gets a float and stores the facet as such. This is, unfortunately, a limitation of the JSON format and the fact that facets don’t have a fixed type.

I would recommend setting a property on a node (instead of facet) if the type is important to you or using the RDF mutation format.

Originally posted by @pawanrawal in Bug: Mutation issue with facets integer · Issue #3 · dgraph-io/dgo · GitHub

This seems like a more general problem affecting node predicates as well. It seems at the moment, the only choices are:

  1. use mutation JSON, in which case I can’t get my integers back out of the database, because they get converted to floats during unmarshalling
  2. Use NQuads and construct them myself.

In my use case, I have dynamic data, and I don’t know what it looks like ahead of time, so I cannot unmarshal into a predefined struct.

I think a modified json.Unmarshaler which does not coerce ints might be helpful. Perhaps the standard lib code could be repurposed and modified relatively easily…

jvsteiner commented :

on second thought, anything that traverses the wire as JSON isn’t going to work. Maybe then, some helper methods to construct the relevant NQuads from the users structs or proto.Messages?

mangalaman93 commented :

@jvsteiner I am not able to reproduce this issue. I ran the following code:

package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/dgraph-io/dgo/v2"
	"github.com/dgraph-io/dgo/v2/protos/api"
	"google.golang.org/grpc"
)

type GraphCollection struct {
	Uid    string      `json:"uid"`
	Weight []GraphNode `json:"weight,omitempty"`
}

type GraphNode struct {
	Uid          string `json:"uid"`
	WeightFacets int64  `json:"weight|score,omitempty"`
}

func main() {
	data := GraphCollection{
		Weight: []GraphNode{
			{
				WeightFacets: 1,
			},
		},
	}

	conn, err := grpc.Dial("localhost:9180", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}
	dg := dgo.NewDgraphClient(api.NewDgraphClient(conn))
	dg.Login(context.Background(), "groot", "password")

	err = dg.Alter(context.Background(), &api.Operation{DropAll: true})
	if err != nil {
		panic(err)
	}
	pb, err := json.Marshal(data)
	if err != nil {
		panic(err)
	}

	ctx := context.Background()
	_, err = dg.NewTxn().Mutate(ctx, &api.Mutation{SetJson: pb, CommitNow: true})
	if err != nil {
		panic(err)
	}

	q := fmt.Sprintf(`{
	  me(func: has(weight)) {
	    weight @facets {
	      uid
	    }
	  }
	}`)

	txn := dg.NewTxn()
	resp, err := txn.Query(ctx, q)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(resp.Json))
}

and response was:

{"me":[{"weight":[{"uid":"0x10"}],"weight|score":{"0":1}}]}

let me know if I am doing something wrong.

mangalaman93 commented :

Closing this issue for now, feel free to reopen.