Sequelize WHERE sequelize.fn(...) AND something='something' 排序问题

Cha*_*ase 6 postgis node.js sequelize.js

我有一个 Sequelize findOne 函数,用于选择给定点与多边形相交的行(col 'geom')AND status = 'active'。

var point = sequelize.fn('ST_GeomFromText', 'POINT(' + lng + ' ' + lat +')', 4326);
var intersects = sequelize.fn('ST_Intersects', sequelize.col('geom'), point);

GeoCounty.findOne({
  attributes: ['id', 'name' ],
  where: {
    status: 'active',
    $and: intersects
  },
  plain: true
})
Run Code Online (Sandbox Code Playgroud)

截至目前,它工作得很好。它生成的 SQL 如下所示:

SELECT "id", "name" FROM "geocounty" AS "geocounty" WHERE "geocounty"."status" = 'active' AND (ST_Intersects("geom", ST_GeomFromText('POINT(-98.025006 43.714735)', 4326))) LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

我真正想要的是:

SELECT "id", "name" FROM "geocounty" AS "geocounty" WHERE (ST_Intersects("geom", ST_GeomFromText('POINT(-98.025006 43.714735)', 4326))) AND "geocounty"."status" = 'active' LIMIT 1;    
Run Code Online (Sandbox Code Playgroud)

也就是说 ST_Intersects 子句在前,AND status='active' 在后。

我的问题是:
1. 以第一种有效的方式执行查询是否有任何性能损失?2. 有没有办法在 Sequelize 中构造像这样的 where 子句?

这不起作用:

GeoCounty.findOne({
  attributes: ['id', 'name' ],
  where: {
    intersects,
    $and: {
      status: 'active'
    }
  },
  plain: true
})    
Run Code Online (Sandbox Code Playgroud)

它产生这个 SQL:

SELECT "id", "name" FROM "geocounty" AS "geocounty" WHERE "geocounty"."intersects" = ST_Intersects("geom", ST_GeomFromText('POINT(-98.025006 43.714735)', 4326)) AND ("geocounty"."status" = 'active') LIMIT 1;    
Run Code Online (Sandbox Code Playgroud)

没有 geocounty.intersects...

小智 10

我在搜索类似问题时偶然发现了这篇文章,并为我找到了一个解决方案,这可能会帮助您解决 #2。

我将函数调用包装到一个额外的地方。我的代码看起来像这样(在 NodeJs 10.9.0 中工作,在 MariaDB 上使用 Sequelize 4.38.0):

Cat.findOne({
  where: {
    color: 'red',
    $and: sequelize.where(sequelize.fn('char_length', sequelize.col('cat_name')), 5)
  }
});
SELECT id, cat_name, color FROM cat_table WHERE color = 'red' AND char_length(cat_name) = 5;
Run Code Online (Sandbox Code Playgroud)

在您的示例中,它看起来像这样(未测试):

var intersects = sequelize.fn('ST_Intersects', sequelize.col('geom'), point);
GeoCounty.findOne({
  attributes: ['id', 'name' ],
  where: {
    $and: sequelize.where(intersects, 1),
    status: 'active'
  },
  plain: true
})
Run Code Online (Sandbox Code Playgroud)