4

can't find whether this has been asked before or not, so bear with me.
I'm just starting to use Neo4j with a nodejs backend and the neo4j-driver driver. I wonder if it's possible to create a node with several properties without enumerating each one in the second argument to the session.run method.

app.post("/signup", function(req, res) {
    var user = req.body; //{userId: "johnsmith", email: "john@smith.com", ...}
    session.run("CREATE (u:User {u}) RETURN u", user).then(function(response) {
        /*do stuff with newly created user*/
    }, function() {
        //handle error
    });
});

Currently, this yields the following error: {code: 'Neo.ClientError.Statement.ParameterMissing', message: 'Expected a parameter named u' }, and if I change the above to:

app.post("/signup", function(req, res) {
    var user = req.body; //{userId: "johnsmith", email: "john@smith.com", ...}
    session.run("CREATE (u:User {u}) RETURN u", {u: user}).then(function(response) {
        /*do stuff with newly created user*/
    }, function() {
        //handle error
    });
});

then the error reads: { code: 'Neo.ClientError.Statement.TypeError', message: 'Property values can only be of primitive types or arrays thereof' }.

This doesn't make much sense to me, given that the refcard clearly states you can create a node using a map, like so: CREATE (n {map}); so I must obviously be getting something wrong. I hope I don't have to enumerate all a user's properties like so:

session.run("CREATE (u:User {userId: {u.userId}, email: {u.email}, ...}) RETURN u", {u: user}).then(/*...*/)

Thanks in advance

Andrea Aloi
  • 971
  • 1
  • 17
  • 37

2 Answers2

2

For example:

app.post("/signup", function(req, res) {
    var params = {};
    //{userId: "johnsmith", email: "john@smith.com", ...}
    Object.keys(req.body).forEach( function(k) {
        var value = req.body[k];
        if (!isPrimitive(val)) value = JSON.stringify(value);
        params[k] = value;
    });

    session.run("CREATE (u:User) SET u = {user} RETURN u", {user: params})
        .then(function(response) {
            // do stuff with newly created user
        }, function() {
            // handle error
        });
});

Where isPrimitive an abstract function that checks whether a variable is a primitive.

stdob--
  • 28,222
  • 5
  • 58
  • 73
  • I'm going to mark this as the correct answer, although I'm not very impressed since the ref card says nested properties are supported, but apparently they're not. – Andrea Aloi Feb 15 '17 at 21:38
  • The ref card needs to be a bit more clear. Nested maps *are* supported for maps, in general. For instance, you can freely pass in JSON data as Cypher query parameters. However, nested maps are NOT supported for storing as property values. I have added a note to my alternate answer. – cybersam Feb 16 '17 at 14:53
2

Neo4j only supports storing specific kinds of data structures to a property. To quote from the Cypher Refcard:

Neo4j properties can be strings, numbers, booleans or arrays thereof.

And, to be more exact, in order for an array (or "collection") to be stored as a property value, all its elements must be of the same primitive type.

The answer from @stdob-- provides one possible simple workaround to this (but it stringifies all arrays, even ones that can be stored without conversion).

NOTE: The refacrd needs to be a bit more clear. Nested maps are supported, in general. For instance, you can freely pass in JSON data as Cypher query parameters. However, maps containing nested maps are NOT supported for storing as property values.

cybersam
  • 63,203
  • 6
  • 53
  • 76