Skip to content
This repository has been archived by the owner on Sep 3, 2021. It is now read-only.

How to modify a property with a mutation request? #571

Open
michaeldgraham opened this issue Jan 15, 2021 · 2 comments
Open

How to modify a property with a mutation request? #571

michaeldgraham opened this issue Jan 15, 2021 · 2 comments

Comments

@michaeldgraham
Copy link
Collaborator

Taken from this post on the Neo4j Community Forum.

I have article nodes in a Neo4j database. One of his property is a boolean: "saved: false". The property name of this node is "saved".

I have a React interface where I want users to be able to save articles as favorites. So what I would like to do is change the property "saved" to true when they want to save an article or set to false when they want to cancel the favorite.

This process can be done with a graphql request but I don't know how to write my request to modify a node property.

Example: The user wants to save the article with id = 1, so he clicks on the button "favorite" and the article node property id = 1 and the node property "saved" goes from false to true.

I just want to update a node property, like this I think:

type Mutations {
    saved(article:ID!) : ??? (string ?)
      @cypher(statement:"MATCH (a:Article {id: $id, saved:$saved})
                         SET a.saved += true ")
}
schema {
   mutations: Mutations
}

How can I do it ?

@michaeldgraham
Copy link
Collaborator Author

There are some options for how to approach mutation design, hopefully we can figure how something that will work for you! 🚀

If you have an Article type similar to the below example, then node update mutations should be available if you're using makeAugmentedSchema to generate default API:

Default Mutations

const typeDefs = `
  type Article {
    id: ID! @id
    saved: Boolean
  }
`;
const schema = makeAugmentedSchema({
  typeDefs
});

Node update mutations generated with the default argument format have input arguments at the root level. These mutations can be overwritten, but it's important to remember that the primary key of a node type, in this case the id field, is always the first mutation argument:

type Mutation {
  CreateArticle(id: ID, saved: Boolean!): Article
  UpdateArticle(id: ID!, saved: Boolean): Article
  DeleteArticle(id: ID!): Article
  MergeArticle(id: ID!, saved: Boolean): Article
}

The UpdateArticle mutation could be used to update the Article.saved property,

mutation Mutation {
  UpdateArticle(
    id: "1"
    saved: true
  ) {
    id
    saved
  }
}

which would result in the below Cypher translation:

MATCH (`article`:`Article`{id: $params.id})
SET `article` += {saved:$params.saved} 
RETURN `article` { .id , .saved } AS `article`

Complex Mutations

A complex format for mutation arguments is available with this experimental flag when configuring schema augmentation. This format generates input types used for node selection and input data:

const schema = makeAugmentedSchema({
  typeDefs,
  config: {
    experimental: true
  }
});
type Mutation {
  CreateArticle(data: _ArticleCreate!): Article
  UpdateArticle(where: _ArticleWhere!, data: _ArticleUpdate!): Article
  DeleteArticle(where: _ArticleWhere!): Article
  MergeArticle(where: _ArticleKeys!, data: _ArticleCreate!): Article
}

So in this format of node update mutations, we can provide the arguments with some added composition:

mutation Mutation {
  UpdateArticle(
    where: {
      id: "1"
    }
    data: {
      saved: true
    }
  ) {
    id
    saved
  }
}
MATCH (`article`:`Article`) WHERE (`article`.id = $where.id)
SET `article` += {saved:$data.saved}
RETURN `article` { .id , .saved } AS `article`

Regardless of whether you use schema augmentation, you can still write your own mutations of the same names, in either format, and they should still be translated. This can be useful to limit which arguments are available, add directives not otherwise generated, or customize the translation logic using a @cypher directive on the mutation field.

Custom Mutations

The @cypher directive can be used on Mutation fields to design custom mutations, similar to how it is used in the Query API. So if the generated update mutations are too general, or you're not augmenting the schema, you could write a @cypher mutation to only set Article.saved to true:

type Mutation {
  SaveArticle(id: ID!): Article @cypher(statement: """
    MATCH (article: Article {
      id: $id
    })
    SET article.saved = TRUE
    RETURN article
  """)
}
mutation Mutation {
  SaveArticle(
    id: "1"
  ) {
    id
    saved
  }
}
Cypher
CALL apoc.cypher.doIt("
  MATCH (article: Article {
    id: $id
  })
  SET article.saved = TRUE
  RETURN article
", {
  id:$id
})
YIELD value
WITH apoc.map.values(value, [keys(value)[0]])[0] AS `article`
RETURN `article` { .id , .saved } AS `article`

@michaeldgraham
Copy link
Collaborator Author

#608

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant