Inserting
Inserting is similar as what it is in with Ecto, except that we have to use Ecto.Adapters.Neo4j.insert/3
instead of the classic insert/2
in order to have our relationships created.
Inserting nodes
It's straight forward as there is nothing more or less than in classic ecto.
# Direct
alias GraphApp.Account.User
alias Ecto.Adapters.Neo4j
user = %User{
uuid: "12903da6-5d46-417b-9cab-bd82766c868b",
firstName: "John",
lastName: "Doe"
}
{:ok, user} = Neo4j.insert(GraphApp.Repo, user)
# Result
{:ok,
%GraphApp.Account.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "User">,
firstName: "John",
has_userprofile: #Ecto.Association.NotLoaded<association :has_userprofile is not loaded>,
lastName: "Doe",
read_post: #Ecto.Association.NotLoaded<association :read_post is not loaded>,
uuid: "12903da6-5d46-417b-9cab-bd82766c868b",
wrote_comment: #Ecto.Association.NotLoaded<association :wrote_comment is not loaded>,
wrote_post: #Ecto.Association.NotLoaded<association :wrote_post is not loaded>
}}
# Through changeset
data = %{
uuid: "12903da6-5d46-417b-9cab-bd82766c868b",
firstName: "John",
lastName: "Doe"
}
changeset = Ecto.Changeset.change(%User{}, data)
{:ok, user} = Neo4j.insert(GraphApp.Repo, changeset)
# Result
{:ok,
%GraphApp.Account.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "User">,
firstName: "John",
has_userprofile: #Ecto.Association.NotLoaded<association :has_userprofile is not loaded>,
lastName: "Doe",
read_post: #Ecto.Association.NotLoaded<association :read_post is not loaded>,
uuid: "12903da6-5d46-417b-9cab-bd82766c868b",
wrote_comment: #Ecto.Association.NotLoaded<association :wrote_comment is not loaded>,
wrote_post: #Ecto.Association.NotLoaded<association :wrote_post is not loaded>
}}
Inserting nodes AND relationships
The only way to insert a lot of nodes and relationship at once required that we know the data to insert. Changeset won't work here.
But it worths the shot as it allows us to insert a complete graph in one command!
Just remember that relationship properties are set on child node. If no properties is required, just set the field to %{}
.
For example:
comment1_data = %Comment{
uuid: "2be39329-d9b5-4b85-a07f-ee9a2997a8ef",
text: "This a comment from john Doe",
# These are the properties for the :WROTE relationship
rel_wrote: %{when: ~D[2018-06-18]},
# These are the properties for the :HAS relationship
rel_has: %{}
}
Now let's insert this graph:
alias GraphApp.Account.{User, UserProfile}
alias GraphApp.Blog.{Post, Comment}
alias Ecto.Adapters.Neo4j
comment1_data = %Comment{
uuid: "2be39329-d9b5-4b85-a07f-ee9a2997a8ef",
text: "This a comment from john Doe",
rel_wrote: %{when: ~D[2018-06-18]},
rel_has: %{}
}
comment2_data = %Comment{
uuid: "e923428a-6819-47ab-bfef-ca4a2e9b75c3",
text: "This is not the best post I've read...",
rel_wrote: %{when: ~D[2018-07-01]},
rel_has: %{}
}
post1_data = %Post{
uuid: "ae830851-9e93-46d5-bbf7-23ab99846497",
title: "First",
text: "This is the first",
rel_wrote: %{
when: ~D[2018-01-01]
},
has_comment: [
comment1_data,
comment2_data
]
}
post2_data = %Post{
uuid: "727289bc-ec28-4459-a9dc-a51ee6bfd6ab",
title: "Second",
text: "This is the second",
rel_read: %{},
rel_wrote: %{
when: ~D[2018-02-01]
}
}
user_profile = %UserProfile{
uuid: "0f364433-c0d2-47ac-ad9b-1dc15bd40cde",
avatar: "user_avatar.png",
rel_has: %{}
}
user = %User{
uuid: "12903da6-5d46-417b-9cab-bd82766c868b",
firstName: "John",
lastName: "Doe",
read_post: [
post2_data
],
wrote_post: [
post1_data,
post2_data
],
wrote_comment: [
comment1_data,
comment2_data
],
has_userprofile: user_profile
}
{:ok, user} = Neo4j.insert(GraphApp.Repo, user)
# Result
{:ok,
%GraphApp.Account.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "User">,
firstName: "John",
has_userprofile: %GraphApp.Account.UserProfile{
__meta__: #Ecto.Schema.Metadata<:loaded, "UserProfile">,
avatar: "user_avatar.png",
has_userprofile: #Ecto.Association.NotLoaded<association :has_userprofile is not loaded>,
has_userprofile_uuid: "12903da6-5d46-417b-9cab-bd82766c868b",
rel_has: %{},
uuid: "0f364433-c0d2-47ac-ad9b-1dc15bd40cde"
},
lastName: "Doe",
read_post: [
%GraphApp.Blog.Post{
__meta__: #Ecto.Schema.Metadata<:loaded, "Post">,
has_comment: #Ecto.Association.NotLoaded<association :has_comment is not loaded>,
read_post: #Ecto.Association.NotLoaded<association :read_post is not loaded>,
read_post_uuid: "12903da6-5d46-417b-9cab-bd82766c868b",
rel_read: %{},
rel_wrote: %{when: ~D[2018-02-01]},
text: "This is the second",
title: "Second",
uuid: "727289bc-ec28-4459-a9dc-a51ee6bfd6ab",
wrote_post: #Ecto.Association.NotLoaded<association :wrote_post is not loaded>,
wrote_post_uuid: nil
}
],
uuid: "12903da6-5d46-417b-9cab-bd82766c868b",
wrote_comment: [
%GraphApp.Blog.Comment{
__meta__: #Ecto.Schema.Metadata<:loaded, "Comment">,
has_comment: #Ecto.Association.NotLoaded<association :has_comment is not loaded>,
has_comment_uuid: nil,
rel_has: %{},
rel_wrote: %{when: ~D[2018-06-18]},
text: "This a comment from john Doe",
uuid: "2be39329-d9b5-4b85-a07f-ee9a2997a8ef",
wrote_comment: #Ecto.Association.NotLoaded<association :wrote_comment is not loaded>,
wrote_comment_uuid: "12903da6-5d46-417b-9cab-bd82766c868b"
},
%GraphApp.Blog.Comment{
__meta__: #Ecto.Schema.Metadata<:loaded, "Comment">,
has_comment: #Ecto.Association.NotLoaded<association :has_comment is not loaded>,
has_comment_uuid: nil,
rel_has: %{},
rel_wrote: %{when: ~D[2018-07-01]},
text: "This is not the best post I've read...",
uuid: "e923428a-6819-47ab-bfef-ca4a2e9b75c3",
wrote_comment: #Ecto.Association.NotLoaded<association :wrote_comment is not loaded>,
wrote_comment_uuid: "12903da6-5d46-417b-9cab-bd82766c868b"
}
],
wrote_post: [
%GraphApp.Blog.Post{
__meta__: #Ecto.Schema.Metadata<:loaded, "Post">,
has_comment: [
%GraphApp.Blog.Comment{
__meta__: #Ecto.Schema.Metadata<:loaded, "Comment">,
has_comment: #Ecto.Association.NotLoaded<association :has_comment is not loaded>,
has_comment_uuid: "ae830851-9e93-46d5-bbf7-23ab99846497",
rel_has: %{},
rel_wrote: %{when: ~D[2018-06-18]},
text: "This a comment from john Doe",
uuid: "2be39329-d9b5-4b85-a07f-ee9a2997a8ef",
wrote_comment: #Ecto.Association.NotLoaded<association :wrote_comment is not loaded>,
wrote_comment_uuid: nil
},
%GraphApp.Blog.Comment{
__meta__: #Ecto.Schema.Metadata<:loaded, "Comment">,
has_comment: #Ecto.Association.NotLoaded<association :has_comment is not loaded>,
has_comment_uuid: "ae830851-9e93-46d5-bbf7-23ab99846497",
rel_has: %{},
rel_wrote: %{when: ~D[2018-07-01]},
text: "This is not the best post I've read...",
uuid: "e923428a-6819-47ab-bfef-ca4a2e9b75c3",
wrote_comment: #Ecto.Association.NotLoaded<association :wrote_comment is not loaded>,
wrote_comment_uuid: nil
}
],
read_post: #Ecto.Association.NotLoaded<association :read_post is not loaded>,
read_post_uuid: nil,
rel_read: nil,
rel_wrote: %{when: ~D[2018-01-01]},
text: "This is the first",
title: "First",
uuid: "ae830851-9e93-46d5-bbf7-23ab99846497",
wrote_post: #Ecto.Association.NotLoaded<association :wrote_post is not loaded>,
wrote_post_uuid: "12903da6-5d46-417b-9cab-bd82766c868b"
},
%GraphApp.Blog.Post{
__meta__: #Ecto.Schema.Metadata<:loaded, "Post">,
has_comment: #Ecto.Association.NotLoaded<association :has_comment is not loaded>,
read_post: #Ecto.Association.NotLoaded<association :read_post is not loaded>,
read_post_uuid: nil,
rel_read: %{},
rel_wrote: %{when: ~D[2018-02-01]},
text: "This is the second",
title: "Second",
uuid: "727289bc-ec28-4459-a9dc-a51ee6bfd6ab",
wrote_post: #Ecto.Association.NotLoaded<association :wrote_post is not loaded>,
wrote_post_uuid: "12903da6-5d46-417b-9cab-bd82766c868b"
}
]
}}
You can notice the presence of wrote_post_uuid
, wrote_comment_uuid
, etc. These are foreign keys and ecto requires them to work properly.
But don't panic, they aren't persisted in database.