I suppose this is partially an SQL question, but I’m wondering how to do this in Ecto.
I have two models that look like so:
defmodule App.Order do
schema "orders" do
field :title, :string
field :description, :string
field :canceled, :boolean, default: false
belongs_to :owner, App.User
has_many :attempts, App.Attempt
timestamps()
end
...
end
defmodule App.Attempt do
schema "attempts" do
field :text, :string
field :accepted, :boolean
belongs_to :owner, App.User
belongs_to :order, App.Order
timestamps()
end
...
end
If possible, I want to craft a single query that gives me all open orders. An order is “open” if all of the following conditions are true:
-
canceled
isfalse
. - The count of attempts where
accepted
istrue
is 0. - The count of attempts where
text
is non-nil
andaccepted
isnil
is 0.
So basically, “select all non-canceled orders where none are explicitly accepted, or none have non-nill text and where accepted
is nil, meaning the attempter has entered text but the client hasn’t explicitly accepted or rejected yet.” New attempts will have accepted
set to nil
and no text, meaning they need text from the attempter and are neither accepted nor rejected pending that text.
Is there any way to structure this in a single Ecto query? Or do I need to add an additional field to my model? While a bit obscure, it seems like the above plus a little documentation is enough for now to capture the states an order might be in, but I can’t wrap my mind around the joins and count checks necessary to list orders meeting this criteria. I can start with attempts, then work back to their orders, but I’m then not sure how I’d sort my orders by when they were last updated, which I also want to do. I suppose I could do that in code, but if the order list ever grew large, this would mean pulling them all from the DB and sorting them in code, plus applying pagination as well.
Thanks for any help. Happy to provide additional information if needed.
As an aside, thanks so much for Ecto, Phoenix, and Elixir. Part of why I’m struggling with Ecto and SQL is because I’ve been in the Mongo/NoSQL world for a while. The only frameworks that have captivated me over the last few years are Meteor and other real-time frameworks, and many of them tended toward Mongo/Redis. I didn’t much like Mongo, but I liked the power the frameworks gave me, so I sort of bit my tongue and slowly lost most of my SQL knowledge. Thanks for giving me an environment that pleases both my pragmatic and correctness-appreciating sides.