2017-01-13 9 views
0

У меня есть модель пользователя в моем проекте phoenixframework с атрибутом дня рождения, который содержит значение Timex.Ecto.Date.Найти следующие дни рождения для празднования

defmodule MyProject.User do 
    use MyProject.Web, :model 

    schema "users" do 
    field :active, :boolean 
    field :birthday, Timex.Ecto.Date 
    field :login, :string 
    field :email, :string 
    field :password, :string, virtual: true 
    field :password_hash, :string 
    field :name, :string 
    field :nickname, :string 

    timestamps 
    end 

    # ... changeset and other code ... 
end 

Теперь я пытаюсь найти всех пользователей, которые отпразднуют свой день рождения в течение следующих 30 дней. Предположим, есть запись пользователя с датой рождения в 1980-02-01. Сегодня 2017-01-13.

Что я сейчас:

{:ok, date_from} = 
    Timex.local 
    |> Timex.Ecto.Date.cast 

{:ok, date_to} = 
    Timex.local 
    |> Timex.add(Timex.Duration.from_days(30)) 
    |> Timex.Ecto.Date.cast 

MyProject.Repo(from(u in MyProject.User, where: u.birthday >= ^date_from, where: u.birthday <= ^date_to)) 

Из года она не может работать. Как мне создать ecto-запрос?

+0

Хотя я не знаю ответа, может быть более полезным спросить сообщество о базе данных, которую вы используете. например, задать вопрос с тегами SQL, если вы используете базу данных SQL. Как только вы знаете, как выполнить необработанный запрос, он должен быть достаточно прямым, чтобы перевести это в ecto. –

+0

Извините, я забыл сказать, что я использую базу данных PostgreSQL. – guitarman

ответ

2

В PostgreSQL я бы использовал age, чтобы получить интервал между датой рождения и теперь, усечь его до года, добавить его к дате рождения, чтобы получить следующий день рождения, а затем посмотреть, находится ли он в следующем 30 дней:

postgres=# select current_date; 
    date 
------------ 
2017-01-14 
(1 row) 

postgres=# select '2000-01-20'::date + date_trunc('year', age('2000-01-20'::date)) + interval '1 year' <= current_date + interval '30 days'; 
?column? 
---------- 
t 
(1 row) 

postgres=# select '2000-02-20'::date + date_trunc('year', age('2000-02-20'::date)) + interval '1 year' <= current_date + interval '30 days'; 
?column? 
---------- 
f 
(1 row) 

с Ecto, это должно выглядеть так (непроверенные):

from(u in User, where: fragment("? + date_trunc('year', age(?)) + interval '1 year' <= current_date + interval '30 days'", u.birthday, u.birthday)) 

это тривиально теперь изменить интервал '1 month' и PostgreSQL будет правильно добавить количество дней в текущем месяц и дать лет u пользователи, у которых есть свой день рождения в течение 1 месяца, а не в течение 30 дней.

+0

OP: этот ответ определенно лучше это мое. – mudasobwa

+0

Это очень хорошее решение, и оно работает, если я использую его, как вы предлагали. Но если я использую другой параметр, просто чтобы быть гибким, он терпит неудачу: 'days = 30; from (u в User, где: фрагмент («? + date_trunc (« год », возраст (?)) + интервал« 1 год »<= текущий_данец + интервал '? days'", u.birthday, u.birthday,^дней)) ' Это приводит к ошибке: параметры' (ArgumentError) должны быть длиной 0 для запроса% Postgrex.Query' – guitarman

+0

@guitarman try 'interval '1 day' *?'. Также проверьте этот ответ, который я написал несколько дней назад: http://stackoverflow.com/a/41571998/320615. – Dogbert

2

Я ничего не известно о возможности сделать это явно с Ecto, но следующее сырье SQL должен работать для MySQL (WHERE пункт только):

WHERE DAY(bd) > DAY(NOW()) AND MONTH(db) = MONTH(NOW()) 
    OR DAY(bd) <= DAY(NOW()) AND MONTH(db) = MOD(MONTH(NOW()), 12) + 1 

Для изменения PostgreSQL DAY(XXX) в EXTRACT(DAY FROM XXX):

WHERE EXTRACT(DAY FROM bd) > EXTRACT(DAY FROM NOW()) .... 

Эти пункты могут быть использованы в Ecto фрагментах, как есть.

+0

Хорошо, теперь я читал о фрагментах в ecto-запросах. Я попробую его позже вместе с вашим ответом. – guitarman

+0

Черт, я забыл упомянуть фрагменты в своем ответе, но у вас, похоже, есть возможность читать между строк :) – mudasobwa

+0

Технически это вернет дни рождения в ближайшие 1 месяц, а не 30 дней :) – Dogbert

 Смежные вопросы

  • Нет связанных вопросов^_^