Этот запрос является перекрестным соединением
(но синтаксис Knex это немного маскирует).
Возвращает любую строку, содержащую aj, e или p в столбце (и одна и та же строка несколько раз по какой-то причине).
Он не возвращает одну и ту же строку несколько раз. Он возвращает все из каждой таблицы, названной в CROSS JOIN
. Это поведение Postgres, когда в предложении FROM
указано несколько таблиц (см .: docs ). Это:
db
.select('*')
.from({
a: 'table_one',
b: 'table_two'
})
будет возвращать всю строку из каждой из названных таблиц каждый раз, когда вы получаете ILIKE
совпадение. Таким образом, как минимум, вы всегда будете объектом, состоящим из двух соединенных строк (или сколько бы вы ни назвали в предложении FROM
).
Сложность в том, что имена столбцов Knex должны соответствовать объектам JavaScript. Это означает, что если есть два столбца с именами, скажем, id
или title
, последний из них перезапишет первый в результирующем объекте.
Давайте проиллюстрируем (вомбатами)
Вот миграция и начальное число, просто для ясности:
table_one
exports.up = knex =>
knex.schema.createTable("table_one", t => {
t.increments("id");
t.string("title");
});
exports.down = knex => knex.schema.dropTable("table_one");
table_two
exports.up = knex =>
knex.schema.createTable("table_two", t => {
t.increments("id");
t.string("title");
});
exports.down = knex => knex.schema.dropTable("table_two");
Seed
exports.seed = knex =>
knex("table_one")
.del()
.then(() => knex("table_two").del())
.then(() =>
knex("table_one").insert([
{ title: "WILLMATCHwombatblahblahblah" },
{ title: "WILLMATCHWOMBAT" }
])
)
.then(() =>
knex("table_two").insert([
{ title: "NEVERMATCHwwwwwww" },
{ title: "wombatWILLMATCH" }
])
)
);
Запрос
Это позволяет нам немного поиграть с ILIKE
соответствием. Теперь нам нужно сделать имена столбцов действительно явными:
return db
.select([
"a.id as a.id",
"a.title as a.title",
"b.id as b.id",
"b.title as b.title"
])
.from({
a: "table_one",
b: "table_two"
})
.where("a.title", "ilike", `%${term}%`)
.orWhere("b.title", "ilike", `%${term}%`);
Это приведет к:
[
{
'a.id': 1,
'a.title': 'WILLMATCHwombatblahblahblah',
'b.id': 1,
'b.title': 'NEVERMATCHwwwwwww'
},
{
'a.id': 1,
'a.title': 'WILLMATCHwombatblahblahblah',
'b.id': 2,
'b.title': 'wombatWILLMATCH'
},
{
'a.id': 2,
'a.title': 'WILLMATCHWOMBAT',
'b.id': 1,
'b.title': 'NEVERMATCHwwwwwww'
},
{
'a.id': 2,
'a.title': 'WILLMATCHWOMBAT',
'b.id': 2,
'b.title': 'wombatWILLMATCH'
}
]
Как вы можете видеть, это перекрестное объединение обеих таблиц, но я подозреваю, что вы были тольковидим результаты, которые оказались не соответствующими (потому что совпадение было в другой таблице, а имя столбца title
было дубликатом).
Итак, каким должен быть запрос?
Я думаю, ваш (или Ry) план использовать UNION
был верным, но, вероятно, стоит использовать UNION ALL
, чтобы избежать ненужного удаления дубликатов. Примерно так:
return db
.unionAll([
db("market_place")
.select(db.raw("*, 'marketplace' as type"))
.where("title", "ilike", `%${term}%`),
db("messageboard_posts")
.select(db.raw("*, 'post' as type"))
.where("title", "ilike", `%${term}%`),
db("rentals")
.select(db.raw("*, 'rental' as type"))
.where("title", "ilike", `%${term}%`),
db("jobs")
.select(db.raw("*, 'job' as type"))
.where("title", "ilike", `%${term}%`)
]);
Аналогичный запрос к нашим тестовым данным дает набор результатов:
[
{ id: 1, title: 'WILLMATCHwombatblahblahblah', type: 'table_one' },
{ id: 2, title: 'WILLMATCHWOMBAT', type: 'table_one' },
{ id: 2, title: 'wombatWILLMATCH', type: 'table_two' }
]