Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use Mix.Config

config :ecto_jsonb_example,
ecto_repos: [EctoJsonbExample.Repo]
config :ecto_jsonb_example, ecto_repos: [EctoJsonbExample.Repo]

import_config "#{Mix.env}.exs"
import_config "#{Mix.env()}.exs"
5 changes: 3 additions & 2 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ config :ecto_jsonb_example, EctoJsonbExample.Repo,
hostname: "localhost",
pool: Ecto.Adapters.SQL.Sandbox,
ownership_timeout: 300_000
# loggers: [{Ecto.LogEntry, :log, [:info]}],
# log_level: :debug

# loggers: [{Ecto.LogEntry, :log, [:info]}],
# log_level: :debug
2 changes: 1 addition & 1 deletion lib/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ defmodule EctoJsonbExample.Application do
import Supervisor.Spec, warn: false

children = [
supervisor(EctoJsonbExample.Repo, [])
supervisor(EctoJsonbExample.Repo, [])
]

opts = [strategy: :one_for_one, name: EctoJsonbExample.Supervisor]
Expand Down
10 changes: 5 additions & 5 deletions lib/models/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ defmodule EctoJsonbExample.User do
use Ecto.Schema

schema "users" do
field :name, :string
field :settings, :map
field :settings_index, :map
field :acls, {:array, :integer}
field :acls_index, {:array, :integer}
field(:name, :string)
field(:settings, :map)
field(:settings_index, :map)
field(:acls, {:array, :integer})
field(:acls_index, {:array, :integer})
end
end
20 changes: 13 additions & 7 deletions priv/repo/migrations/20171029173051_create_users.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@ defmodule EctoJsonbExample.Repo.Migrations.CreateUsers do

def up do
create table("users") do
add :name, :string, null: false
add :settings, :jsonb, null: false, default: "{}"
add :settings_index, :jsonb, null: false, default: "{}"
add :acls, :jsonb, null: false, default: "[]"
add :acls_index, :jsonb, null: false, default: "[]"
add(:name, :string, null: false)
add(:settings, :jsonb, null: false, default: "{}")
add(:settings_index, :jsonb, null: false, default: "{}")
add(:acls, :jsonb, null: false, default: "[]")
add(:acls_index, :jsonb, null: false, default: "[]")
end

execute("CREATE INDEX users_settings_index_providers ON users USING GIN ((settings_index->'providers'))")
execute("CREATE INDEX users_settings_index_roles ON users USING GIN ((settings_index->'roles'))")
execute(
"CREATE INDEX users_settings_index_providers ON users USING GIN ((settings_index->'providers'))"
)

execute(
"CREATE INDEX users_settings_index_roles ON users USING GIN ((settings_index->'roles'))"
)

execute("CREATE INDEX users_acls_index ON users USING GIN ((acls_index))")
end
end
52 changes: 25 additions & 27 deletions priv/repo/search.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,48 @@ alias EctoJsonbExample.Repo
alias EctoJsonbExample.User
import Ecto.Query, only: [from: 2]

IO.puts "Select users with admin role"
query = from u in User,
where: fragment("(settings_index->'roles')::jsonb \\? ?", "admin")
IO.puts("Select users with admin role")
query = from(u in User, where: fragment("(settings_index->'roles')::jsonb \\? ?", "admin"))

result = Repo.all(query)
IO.inspect result
IO.inspect(result)

IO.puts "Select users by acls"
query = from u in User,
where: fragment("acls_index @> ?", ^[101])
IO.puts("Select users by acls")
query = from(u in User, where: fragment("acls_index @> ?", ^[101]))

roles_result = Repo.all(query)
IO.inspect roles_result
IO.inspect(roles_result)

IO.puts "Select users by loyalty"
query = from u in User,
where: fragment("(settings_index)::jsonb @> ?::jsonb", ^%{loyalties: 101})
IO.puts("Select users by loyalty")

query =
from(u in User, where: fragment("(settings_index)::jsonb @> ?::jsonb", ^%{loyalties: 101}))

result = Repo.all(query)
IO.inspect result
IO.inspect(result)

IO.puts "Select users - all with key personal_info"
query = from u in User,
where: fragment("(settings_index)::jsonb \\? ?", "personal_info")
IO.puts("Select users - all with key personal_info")
query = from(u in User, where: fragment("(settings_index)::jsonb \\? ?", "personal_info"))

result = Repo.all(query)
IO.inspect result
IO.inspect(result)

IO.puts("Roles search benchmark with index vs without index")

IO.puts "Roles search benchmark with index vs without index"
index_role_query = fn ->
query = from u in User,
where: fragment("(settings_index->'roles')::jsonb \\? ?", "admin")
query = from(u in User, where: fragment("(settings_index->'roles')::jsonb \\? ?", "admin"))
Repo.all(query)
end

no_index_role_query = fn ->
query = from u in User,
where: fragment("(settings->'roles')::jsonb \\? ?", "admin")
query = from(u in User, where: fragment("(settings->'roles')::jsonb \\? ?", "admin"))
Repo.all(query)
end

Benchee.run(%{
"with index" => index_role_query,
"without index" => no_index_role_query
}, time: 10)


Benchee.run(
%{
"with index" => index_role_query,
"without index" => no_index_role_query
},
time: 10
)
52 changes: 32 additions & 20 deletions priv/repo/seeds.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,48 @@ alias EctoJsonbExample.Repo
alias EctoJsonbExample.User

roles = ["user", "driver", "manager", "support", "technician", "guest"]
providers = ["facebook", "google", "twitter", "github", "foursquare", "dropbox", "linkedin", "vimeo"]

providers = [
"facebook",
"google",
"twitter",
"github",
"foursquare",
"dropbox",
"linkedin",
"vimeo"
]

for i <- 1..1_000_000 do
selected_providers = Enum.take_random(providers, 2)
selected_roles = Enum.take_random(roles, 2)
settings = if rem(i, 250_000) == 0 do
%{
roles: ["admin", Enum.random(selected_roles)]
loyalties: :rand.uniform(1_000),
providers: selected_providers,
personal_info: "Gigi"
}
else
%{
roles: selected_roles,
loyalties: :rand.uniform(1_000),
providers: selected_providers
}
end

settings =
if rem(i, 250_000) == 0 do
%{
roles: ["admin", Enum.random(selected_roles)],
loyalties: :rand.uniform(1000),
providers: selected_providers,
personal_info: "Gigi"
}
else
%{
roles: selected_roles,
loyalties: :rand.uniform(1000),
providers: selected_providers
}
end

acls = for _ <- 1..4, do: :rand.uniform(100)
acls = if rem(i, 250_000) == 0, do: acls ++ [101], else: acls


Repo.insert! %User{
name: Faker.Name.name,
Repo.insert!(%User{
name: Faker.Name.name(),
settings: settings,
settings_index: settings,
acls: acls,
acls_index: acls
}
IO.puts "inserting user #{i}/1_000_000"
})

IO.puts("inserting user #{i}/1_000_000")
end