【问题标题】:Storing and querying PostgreSQL database entities with multiple related entities?存储和查询具有多个相关实体的 PostgreSQL 数据库实体?
【发布时间】:2020-01-07 14:59:00
【问题描述】:

设计一个 PostgreSQL 数据库,该数据库将由使用 Sequelize 的 Node API 查询。目前,我有一个名为recipes 的表,其中包含名为ingredientsinstructions 的列。这些列存储为给定的字符串数组,如{Tomatoes, Onions}

这种存储方法非常适合在客户端简单地获取和呈现配方。但它不适用于模糊搜索查询,因为使用 Sequelize 我所能做的就是ingredients: { [Op.contains] : [query] }。因此,如果用户键入tomatoes,则无法编写一个“模糊”搜索查询来返回包含Tomatoes 成分的食谱。

然后我在 PostgreSQL 文档中读到了这个:

数组不是集合;搜索特定的数组元素可能是数据库设计错误的标志。考虑使用一个单独的表,其中每个项目将是一个数组元素。这将更容易搜索,并且对于大量元素可能会更好地扩展。

现在我正在考虑将ingredientsinstructions 存储为单独的表,但我有几个问题。

1) 由于一个食谱可以有多个相关的成分,我应该只为每个成分使用一个外键和 Sequelize hasMany 关系吗?这对我来说似乎是正确的,只是现在每次创建使用该成分的新配方时,我都有可能复制常见成分。

2) 编写模糊搜索查询的最佳方法是什么,以便用户可以搜索recipes 表的主要列(例如titledescription)并将他们的查询附加到@ 987654337@ 和 ingredients 表?

基本上,我想最终将模糊搜索查询应用于三个看起来像这样的表......

        const recipes = await req.context.models.Recipe.findAll({
        where: {
          [Op.or]: [
            { title: { [Op.iLike]: '%' + query + '%' } },
            { description: { [Op.iLike]: '%' + query + '%' } },
            { ingredients: { ingredient: { [Op.iLike]: '%' + query + '%' } } },
            { instructions: { instruction: { [Op.iLike]: '%' + query + '%' } } }
          ]
        }
      });

谢谢!

【问题讨论】:

标签: node.js postgresql sequelize.js


【解决方案1】:

我已经这样做了,我碰巧在我的节点层中使用了带有 sequelize 的 graphql,并且我有过滤器对象来做这种事情。您只需要在您的 Recipie.findAll.. 中包含一些语句,在您评估您是在搜索标题还是描述或两者都输入的东西的初始 where 子句之后。我用前缀发送了我的搜索参数,我可以去掉它告诉我我想在它们上使用什么 sequelize op,然后通过一个实用方法运行我的 args 来创建我的 where 子句,但我知道有很多方法可以剥皮猫。我只是不想用大量的硬编码操作和条件子句把我的解析器搞得一团糟……你的包含可能看起来像这样

    include: [{
              model: models.Ingredient,
              as: 'Ingredients',
              through: { some join table specifying keys where necessary since this 
                         is many to many }
              where: {some conditional code around your search param},
            }, {
              model: models.Instruction,
              as: 'Instructions',
              where: {some conditional code around your search param},
            }],

在 sequelize 文档中有关于多个包含或嵌套包含的良好文档,但从我上面看到的内容来看,您对您需要做什么有相当好的理解。为了让事情变得简单一点,我会先从接收者(标题,描述)中搜索你的字段,然后再添加包含并让它工作,然后你想如何形成你的 where 子句会更清楚一点。

alternativley..您可以跳过包含并在模型中编写关联并使用 getter 调用它们并将 where 子句传递给那些...游戏

Recipie.associate = function (models) {
    models.Recipie.hasMany(models.Ingredient, { as: 'Ingredients', through: "recipie_ingredient" foreignKey: 'recipie_id'});
  };

现在您有一个用于成分的吸气剂,如果您在成分模型中声明belongsToMany 以返回Recipie 为目标,那么您在那里也将有一个吸气剂,您可以通过where 子句将您的搜索字符串传递给该吸气剂并获取所有具有给定成分或成分列表类型的东西的食谱......像泥一样清除?

【讨论】:

  • 谢谢!我认为第二个选项是我可能去的地方,因为当我定义我的 Recipe 模型时,我已经有一些事情要做了。我对搜索查询的目标是在客户端实现它,以便用户可以返回与其查询相关的任何配方,无论titledescription是否匹配, ingredientsinstructions。我的前半部分为titledescription 工作,但是当我发现我无法对我的ingredientsinstructions 列执行强大的查询时,考虑到我最初的数据库设计.
猜你喜欢
  • 2018-07-18
  • 2019-04-17
  • 2023-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多