knex select 的意外行为
Unexpected behavior with knex's select
对于以下代码,我得到的结果有时是一个数组,有时是一个对象。我想接收数组,即使它是空的。
export const GetByPId = async (userId, pId) => knex('table1').where({ userId, pId }).select(
'userId',
'pId',
'id',
'created',
'updated',
);
在我的业务对象中,我等待响应
static async LoadByPId(userId, pId) {
const data = await GetByPId(userId, pId);
console.log(`result ${JSON.stringify(data)}`);
}
一旦它 returned
[{ userId: 1, id: 1 ...
- 我想要这个
下一次 returned
{ userId: 1, id: 1 ...
- 不想要这个
发生了什么事,我怎样才能让它总是 return 一个数组?
更新 #1
现在只有 return 一个结果。
更新 #2
情况每况愈下。
现在我的其他基本功能无法正常使用。 Knex 仅适用于第一组参数,其他所有参数均无效。
例如,如果 express 服务器重新启动并发送 userId: 1 和 pId: 1 的请求,它会起作用。如果我用相同的参数重复相同的请求,它就可以工作。但是,如果我将参数(即 userId 或 pId)更改为另一个有效集,它将失败。在尝试任何其他参数之前,我必须重新启动快速服务器。我在我的应用程序和邮递员上测试了这个。
我的快递代码如下所示
router.post('/list', auth, async (req, res) => {
try {
const biz= await BizObj.LoadByPId(req.user.id, req.body.pId);
res.json(biz);
} catch (ex) {
console.log(ex);
res.status(400).json('Unauthorized');
}
});
更新 #4
以防我的 knex 配置有问题
development: {
client: 'postgresql',
connection: {
database: 'somedb',
user: 'SOMEUSER',
password: '',
timezone: 'UTC',
},
pool: {
min: 2,
max: 10,
},
migrations: {
tableName: 'knex_migrations',
},
},
更新 #5
单页代码(仅缺少快速设置)
在 pg 数据库 / SomeObj
id userId
1 1
2 2
3 2
代码示例
import knex from 'knex';
import express from 'express';
const config = {
development: {
client: 'pg',
connection: {
database: 'somedb',
user: 'SOMEUSER',
password: '',
timezone: 'UTC',
},
pool: {
min: 2,
max: 10,
},
migrations: {
tableName: 'knex_migrations',
},
},
};
const knexed = knex(config.development);
const SQL = knexed('SomeObj');
const GetAll = async userId => SQL.where({ userId }).select(
'id',
'userId',
);
const GetById = async (userId, id) => SQL.where({ userId, id }).first(
'id',
'userId',
);
class SomeObj {
constructor(data, userId) {
this.userId = userId;
this.id = data.id;
}
static async LoadAll(userId) {
const data = await GetAll(userId);
if (!data || data.length === 0) return null;
return data.map(r => new SomeObj(r, userId));
}
static async Load(userId, id) {
const data = await GetById(userId, id);
if (!data) return null;
return new SomeObj(data, userId);
}
}
const router = express.Router();
router.post('/list', async (req, res) => {
try {
const res1 = await SomeObj.LoadAll(req.body.id); // works and returns array
const res2 = await SomeObj.Load(req.body.id, 2); // fails and returns undefined
res.json({ res1, res2 });
} catch (ex) {
res.status(401).json(ex);
}
});
没有第二个查询可以运行。不知道我是否遗漏了一些简单的关闭连接的方法。
更新 #6
我发誓 knex 在搞乱我。每次我尝试一些东西(并返回确认更改是由于我的新输入)时,都会有不同的响应。现在,res1 和 res2 return 第一个请求的正确结果,但第二个请求失败。
更新 #7
Runkit 示例:https://runkit.com/tristargod/runkit-npm-knex
它对第一个请求运行,但对 express 服务器上的所有其他请求都失败。
更新 #8
有关详细信息,请参阅 https://github.com/tgriesser/knex/issues/2346#issuecomment-346757344。谢谢米凯尔!
knex('table1')
.where({ userId, pId })
.select('userId', 'pId', 'id', 'created', 'updated')
应该return总是一个结果数组。您还做错了示例中未显示的其他事情。
示例代码:https://runkit.com/embed/kew7v2lwpibn
对更新#7 的回应
tldr; Knex 查询生成器是可变的,因此在重新使用它们时 .clone() 是必要的。 https://runkit.com/mikaelle/5a17c6d99cd063001284a20a
很好的例子,从中很容易发现问题
您多次重复使用同一个查询生成器,而没有在查询之间克隆它。如果您 运行 您的代码设置了 DEBUG=knex:*
环境变量,您会发现构造的查询在第一次调用后不正确。
const GetAll = async userId => SQL.clone().where({ userId }).select(
'id',
'userId',
);
const GetById = async (userId, id) => SQL.clone().where({ userId, id }).first(
'id',
'userId',
);
对于以下代码,我得到的结果有时是一个数组,有时是一个对象。我想接收数组,即使它是空的。
export const GetByPId = async (userId, pId) => knex('table1').where({ userId, pId }).select(
'userId',
'pId',
'id',
'created',
'updated',
);
在我的业务对象中,我等待响应
static async LoadByPId(userId, pId) {
const data = await GetByPId(userId, pId);
console.log(`result ${JSON.stringify(data)}`);
}
一旦它 returned
[{ userId: 1, id: 1 ...
- 我想要这个
下一次 returned
{ userId: 1, id: 1 ...
- 不想要这个
发生了什么事,我怎样才能让它总是 return 一个数组?
更新 #1
现在只有 return 一个结果。
更新 #2
情况每况愈下。
现在我的其他基本功能无法正常使用。 Knex 仅适用于第一组参数,其他所有参数均无效。
例如,如果 express 服务器重新启动并发送 userId: 1 和 pId: 1 的请求,它会起作用。如果我用相同的参数重复相同的请求,它就可以工作。但是,如果我将参数(即 userId 或 pId)更改为另一个有效集,它将失败。在尝试任何其他参数之前,我必须重新启动快速服务器。我在我的应用程序和邮递员上测试了这个。
我的快递代码如下所示
router.post('/list', auth, async (req, res) => {
try {
const biz= await BizObj.LoadByPId(req.user.id, req.body.pId);
res.json(biz);
} catch (ex) {
console.log(ex);
res.status(400).json('Unauthorized');
}
});
更新 #4
以防我的 knex 配置有问题
development: {
client: 'postgresql',
connection: {
database: 'somedb',
user: 'SOMEUSER',
password: '',
timezone: 'UTC',
},
pool: {
min: 2,
max: 10,
},
migrations: {
tableName: 'knex_migrations',
},
},
更新 #5 单页代码(仅缺少快速设置)
在 pg 数据库 / SomeObj
id userId
1 1
2 2
3 2
代码示例
import knex from 'knex';
import express from 'express';
const config = {
development: {
client: 'pg',
connection: {
database: 'somedb',
user: 'SOMEUSER',
password: '',
timezone: 'UTC',
},
pool: {
min: 2,
max: 10,
},
migrations: {
tableName: 'knex_migrations',
},
},
};
const knexed = knex(config.development);
const SQL = knexed('SomeObj');
const GetAll = async userId => SQL.where({ userId }).select(
'id',
'userId',
);
const GetById = async (userId, id) => SQL.where({ userId, id }).first(
'id',
'userId',
);
class SomeObj {
constructor(data, userId) {
this.userId = userId;
this.id = data.id;
}
static async LoadAll(userId) {
const data = await GetAll(userId);
if (!data || data.length === 0) return null;
return data.map(r => new SomeObj(r, userId));
}
static async Load(userId, id) {
const data = await GetById(userId, id);
if (!data) return null;
return new SomeObj(data, userId);
}
}
const router = express.Router();
router.post('/list', async (req, res) => {
try {
const res1 = await SomeObj.LoadAll(req.body.id); // works and returns array
const res2 = await SomeObj.Load(req.body.id, 2); // fails and returns undefined
res.json({ res1, res2 });
} catch (ex) {
res.status(401).json(ex);
}
});
没有第二个查询可以运行。不知道我是否遗漏了一些简单的关闭连接的方法。
更新 #6
我发誓 knex 在搞乱我。每次我尝试一些东西(并返回确认更改是由于我的新输入)时,都会有不同的响应。现在,res1 和 res2 return 第一个请求的正确结果,但第二个请求失败。
更新 #7
Runkit 示例:https://runkit.com/tristargod/runkit-npm-knex
它对第一个请求运行,但对 express 服务器上的所有其他请求都失败。
更新 #8
有关详细信息,请参阅 https://github.com/tgriesser/knex/issues/2346#issuecomment-346757344。谢谢米凯尔!
knex('table1')
.where({ userId, pId })
.select('userId', 'pId', 'id', 'created', 'updated')
应该return总是一个结果数组。您还做错了示例中未显示的其他事情。
示例代码:https://runkit.com/embed/kew7v2lwpibn
对更新#7 的回应
tldr; Knex 查询生成器是可变的,因此在重新使用它们时 .clone() 是必要的。 https://runkit.com/mikaelle/5a17c6d99cd063001284a20a
很好的例子,从中很容易发现问题
您多次重复使用同一个查询生成器,而没有在查询之间克隆它。如果您 运行 您的代码设置了 DEBUG=knex:*
环境变量,您会发现构造的查询在第一次调用后不正确。
const GetAll = async userId => SQL.clone().where({ userId }).select(
'id',
'userId',
);
const GetById = async (userId, id) => SQL.clone().where({ userId, id }).first(
'id',
'userId',
);