在How to return a plain value from a Knex / Postgresql query?中,我询问仅从Knex查询中获取列值,而没有包含列名称的JSON对象。建议我使用pluck(fieldName)
。
如果我在查询中返回单个列,那很好。如何返回相似格式的多列?我正在寻找类似pluck([fieldName1, fieldname2])
或pluck(fieldName1, fieldname2)
的东西,对于每一行,返回["value1", "value2"]
答案 0 :(得分:2)
首先让我们回顾一下knex.js当前如何实现pluck,然后看看我们是否能找到适合您需求的可行解决方案。
因此,pluck
所做的本质是修改查询以在选择语句中包含pluck列,然后使用lodash.map处理响应以仅返回pluck字段值的数组(而不是结果对象数组)。这意味着它在内部对查询结果运行lodash.map(resultsArray, pluckColumnName);
之类的东西。
因此,使用小巧的代码示例意味着:
常规查询:
knex('product').limit(10); // regular query
SELECT * FROM `product` LIMIT 10 // translates into wildcard select from the table
[{id: 1, name: 'foo'}, {...}] // result is Array of Objects with all columns from the table
常规查询:
knex('product').limit(10).pluck('id'); // query with pluck
SELECT id FROM `product` LIMIT 10 // translates into specific column select
loadsh.map(results, 'id') // knex internally runs loadsh.map on the results
[1, 2, 3, ...] // we get array of pluck column values back
如果您要选择多个列,则只需将结果映射函数更改为,而不是仅返回单个值即可返回多个值的数组。这可以通过多种方式完成:
解决方案1:
最简单的方法是在查询中手动包括采摘列,然后对结果运行常规Array Map。代码看起来像这样:
// construct the query, make sure the fields you want to get values for are present
// it's best to include them in the .select statement because you really don't care for other fields
const query = knex('product').select('id', 'name').limit(10);
return query
.then(results => {
return results.map(result => [result.id, result.name]);
})
.then(pluckedResults => {
// pluckedResults: [[1, 'foo'], [2, 'bar'], [3, 'etc'], ...]];
return pluckedResults;
});
解决方案2:
可以扩展knex QueryBuilder以在所有查询上提供自定义功能。因此,我们将创建multi-pluck.js
并为knex定义.multiPluck QueryBuilder扩展。
/**
* multi-pluck.js
* We are extending knex QueryBuilder to offer multi column pluck feature
* We add the pluck columns to the original query select statement and process result to return
* only the values of pluck columns in the same order they are defined
*
* Please note that .multiPluck() needs to be last in the chain as it executes the query and breaks
* query chaining.
*/
const QueryBuilder = require('knex/lib/query/builder');
Object.assign(QueryBuilder.prototype, {
multiPluck: function multiPluck (...pluckColumns) {
// add pluck columns to the query.select
this.select(...pluckColumns);
// run the query and map results
return this.then(results => {
// go over all result Objects
return results.map(result => {
// for each result Object, return an array of values for each pluckColumns
return pluckColumns.map(pluckColumn => {
// if pluck column includes table name like product.id, only use id field here
if (pluckColumn.indexOf('.') !== -1) {
pluckColumn = pluckColumn.split('.').slice(-1)[0];
}
// return given column value from this result row
return result[pluckColumn];
});
});
});
}
});
要使用它,您将执行以下操作:
// include the DB connection file which initialises knex connection
const knex = require('./db/connection').knex;
// include our multi-pluck extension
require('./db/multi-pluck');
// example function to get data from DB using the extension
async function getData () {
return knex('product').limit(10).multiPluck('id', 'name');
}
// run the function
getData()
.then(pluckedResults => {
console.log(pluckedResults); // [[1, 'foo'], [2, 'bar'], [3, 'etc'], ...]
})
.catch(err => {
// handle errors as usual
});
请注意,QueryBuilder扩展可以包含在连接初始化文件中,因此您可以在任何地方使用它们。
警告:由于multiPluck实际上运行查询,因此它会断开knex查询链,并且必须是查询上调用的最后一个函数