Knex.js,将“.orWhereExists”嵌套到过滤器字段中以包含针对男性、女性或两者的选项
Knex.js, Nested '.orWhereExists' into filters field to include option for men, women or both
我正在使用 Knex 和 Postgres、NodeJS、Express 和 React。
我有一个 USERS table、一个 USERLIKS 和一个 FILTERS table。
我被卡住的地方是性别查询。
用户可以在他们的过滤器中定义他们正在寻找男性、女性或两者。
如果我使用 '.orWhereExists' 其他过滤器(例如第二个过滤器),它会阻止您返回用户,您已经 liked/rejected 将被忽略。
我的直觉告诉我应该以某种方式嵌套性别查询行,然后将它们更改为“.orWhereExists”,但我不确定该怎么做。
感谢您的帮助。今年刚开始编码并喜欢它,但这个问题一直令人费解
Filters is organized like so
table.increments('id') <-----primary
table.integer('userid') <-----foreign
table.integer('min_age');
table.integer('max_age');
table.string('female');
table.string('male');
app.get('/api/potentials', (req, res) => {
const cookieid = req.session.id
console.log("potentials get for id ", cookieid)
knex('users')
.select('*')
.whereNot('users.id', cookieid )
.whereNotExists(knex.select('*').from('userlikes').whereRaw('userlikes.userid1 = ?', [cookieid]).andWhereRaw('users.id = userlikes.userid2'))
.whereExists(knex.select('*').from('filters').whereRaw('users.gender = filters.female'))
.whereExists(knex.select('*').from('filters').whereRaw('users.gender = filters.male'))
.whereExists(knex.select('*').from('filters').whereRaw('users.age >= filters.min_age'))
.whereExists(knex.select('*').from('filters').whereRaw('users.age < filters.max_age'))
.then((result) => {
console.log("filter result", result)
res.send(result)
})
.catch((err) => {
console.log("error", err)
})
Knex 函数 .buildermodify()
适合您的情况。另见:documentation link.
要使用它,您需要创建一个函数,其目的是有条件地将 .where
或其他类似子句添加到您的 knex 查询中,并且在实际的 knex 查询中,您使用 .buildermodify()
调用该函数
文档中的示例:
var withUserName = function(queryBuilder, foreignKey) {
queryBuilder.leftJoin('users', foreignKey, 'users.id')
.select('users.user_name');
};
knex.table('articles')
.select('title', 'body')
.modify(withUserName, 'articles_user.id')
.then(function(article) {
console.log(article.user_name);
});
将其应用于您获得性别(和年龄)的需要:
/* NEW FUNCTION TO DO THE SPECIAL FILTERING */
function customFiltering(queryBuilder, inputGender, minAge, maxAge) {
if (inputGender === gender_is_female) { /* you need to fix this */
/* THIS LINE IS THE SECRET SAUCE TO CONDITIONALLY UPDATE YOUR QUERY */
/* queryBuilder.<my additional conditional clauses> */
queryBuilder.whereExists( knex.select('*').from('filters')
.whereRaw('users.gender = filters.female'));
} else if (inputGender === gender_is_male) {
queryBuilder.whereExists( knex.select('*').from('filters')
.whereRaw('users.gender = filters.male'));
}
/* ADD MORE CODE HERE for the ages filter - minAge, maxAge */
};
knex('users')
.select('*')
.whereNot('users.id', cookieid )
.whereNotExists( knex.select('*').from('userlikes').whereRaw('userlikes.userid1 = ?', [cookieid]).andWhereRaw('users.id = userlikes.userid2'))
.modify(customFiltering, inputGender, minAge, maxAge)
.then((result) => {
console.log("filter result", result)
res.send(result)
})
.catch((err) => {
console.log("error", err)
})
祝你好运!
对于复杂的查询构建,我通常做的是用普通的 SQL 编写它,然后尝试将其转换为 knex
结构。
据我了解,您正在寻找这样的东西
select
*
from
users as u
where
...
and (
(exists select * from filters as f where f.male = u.gender)
or (exists select * from filters as f where f.female = u.gender)
)
用knex的话可以写成
knex('users as u')
.where('other conditions')
.where((b) => {
b
.whereExists(knex.select('*').from('filters as f').whereRaw('u.gender = f.female'))
.orWhereExists(knex.select('*').from('filters as f').whereRaw('u.gender = f.male'))
})
knex
中可以将您的 where 子句分组在括号中。在 here 中搜索 "Grouped Chain"
A solution someone offline gave me that worked was to use a "promise" but GaryL's solution above is more inline with what I was looking for. In the event it is helpful to people with similar questions this also worked.
> Blockquote
app.get('/api/potentials', (req, res) => {
const cookieid = 1//req.session.id
console.log("potentials get for id ", cookieid)
Promise.all([
knex('users')
.select('filters.min_age','filters.max_age', 'filters.female','filters.male')
.innerJoin('filters', 'users.id', 'filters.userid')
.where('users.id',cookieid ),
knex('users')
.whereNotExists(knex.select('*').from('userlikes').whereRaw('userlikes.userid1 = ?', [cookieid]).andWhereRaw('users.id = userlikes.userid2'))
])
.then((result) => {
const[filterCriteria, users] = result
const [min_age, max_age, female, male] = Object.values(filterCriteria[0])
res.send(users.filter(user => {
if((user.age >= min_age) && (user.age <= max_age) && ( (user.gender = female) || (user.gender = male) || (user.gender = female) && (user.gender = male) ) ) {
return user
}
}))
})
.catch((err) => {
console.log("error", err)
})
})
我正在使用 Knex 和 Postgres、NodeJS、Express 和 React。 我有一个 USERS table、一个 USERLIKS 和一个 FILTERS table。 我被卡住的地方是性别查询。 用户可以在他们的过滤器中定义他们正在寻找男性、女性或两者。
如果我使用 '.orWhereExists' 其他过滤器(例如第二个过滤器),它会阻止您返回用户,您已经 liked/rejected 将被忽略。 我的直觉告诉我应该以某种方式嵌套性别查询行,然后将它们更改为“.orWhereExists”,但我不确定该怎么做。
感谢您的帮助。今年刚开始编码并喜欢它,但这个问题一直令人费解
Filters is organized like so
table.increments('id') <-----primary
table.integer('userid') <-----foreign
table.integer('min_age');
table.integer('max_age');
table.string('female');
table.string('male');
app.get('/api/potentials', (req, res) => {
const cookieid = req.session.id
console.log("potentials get for id ", cookieid)
knex('users')
.select('*')
.whereNot('users.id', cookieid )
.whereNotExists(knex.select('*').from('userlikes').whereRaw('userlikes.userid1 = ?', [cookieid]).andWhereRaw('users.id = userlikes.userid2'))
.whereExists(knex.select('*').from('filters').whereRaw('users.gender = filters.female'))
.whereExists(knex.select('*').from('filters').whereRaw('users.gender = filters.male'))
.whereExists(knex.select('*').from('filters').whereRaw('users.age >= filters.min_age'))
.whereExists(knex.select('*').from('filters').whereRaw('users.age < filters.max_age'))
.then((result) => {
console.log("filter result", result)
res.send(result)
})
.catch((err) => {
console.log("error", err)
})
Knex 函数 .buildermodify()
适合您的情况。另见:documentation link.
要使用它,您需要创建一个函数,其目的是有条件地将 .where
或其他类似子句添加到您的 knex 查询中,并且在实际的 knex 查询中,您使用 .buildermodify()
调用该函数
文档中的示例:
var withUserName = function(queryBuilder, foreignKey) {
queryBuilder.leftJoin('users', foreignKey, 'users.id')
.select('users.user_name');
};
knex.table('articles')
.select('title', 'body')
.modify(withUserName, 'articles_user.id')
.then(function(article) {
console.log(article.user_name);
});
将其应用于您获得性别(和年龄)的需要:
/* NEW FUNCTION TO DO THE SPECIAL FILTERING */
function customFiltering(queryBuilder, inputGender, minAge, maxAge) {
if (inputGender === gender_is_female) { /* you need to fix this */
/* THIS LINE IS THE SECRET SAUCE TO CONDITIONALLY UPDATE YOUR QUERY */
/* queryBuilder.<my additional conditional clauses> */
queryBuilder.whereExists( knex.select('*').from('filters')
.whereRaw('users.gender = filters.female'));
} else if (inputGender === gender_is_male) {
queryBuilder.whereExists( knex.select('*').from('filters')
.whereRaw('users.gender = filters.male'));
}
/* ADD MORE CODE HERE for the ages filter - minAge, maxAge */
};
knex('users')
.select('*')
.whereNot('users.id', cookieid )
.whereNotExists( knex.select('*').from('userlikes').whereRaw('userlikes.userid1 = ?', [cookieid]).andWhereRaw('users.id = userlikes.userid2'))
.modify(customFiltering, inputGender, minAge, maxAge)
.then((result) => {
console.log("filter result", result)
res.send(result)
})
.catch((err) => {
console.log("error", err)
})
祝你好运!
对于复杂的查询构建,我通常做的是用普通的 SQL 编写它,然后尝试将其转换为 knex
结构。
据我了解,您正在寻找这样的东西
select
*
from
users as u
where
...
and (
(exists select * from filters as f where f.male = u.gender)
or (exists select * from filters as f where f.female = u.gender)
)
用knex的话可以写成
knex('users as u')
.where('other conditions')
.where((b) => {
b
.whereExists(knex.select('*').from('filters as f').whereRaw('u.gender = f.female'))
.orWhereExists(knex.select('*').from('filters as f').whereRaw('u.gender = f.male'))
})
knex
中可以将您的 where 子句分组在括号中。在 here 中搜索 "Grouped Chain"
A solution someone offline gave me that worked was to use a "promise" but GaryL's solution above is more inline with what I was looking for. In the event it is helpful to people with similar questions this also worked.
> Blockquote
app.get('/api/potentials', (req, res) => {
const cookieid = 1//req.session.id
console.log("potentials get for id ", cookieid)
Promise.all([
knex('users')
.select('filters.min_age','filters.max_age', 'filters.female','filters.male')
.innerJoin('filters', 'users.id', 'filters.userid')
.where('users.id',cookieid ),
knex('users')
.whereNotExists(knex.select('*').from('userlikes').whereRaw('userlikes.userid1 = ?', [cookieid]).andWhereRaw('users.id = userlikes.userid2'))
])
.then((result) => {
const[filterCriteria, users] = result
const [min_age, max_age, female, male] = Object.values(filterCriteria[0])
res.send(users.filter(user => {
if((user.age >= min_age) && (user.age <= max_age) && ( (user.gender = female) || (user.gender = male) || (user.gender = female) && (user.gender = male) ) ) {
return user
}
}))
})
.catch((err) => {
console.log("error", err)
})
})