有熟练sequelizejs的吗 Nodejs

有熟练sequelizejs的吗 Nodejs

现在项目中再用,数据库是MySQL,现在的实现方式把自己绕进死胡同了

逻辑上是以 customers 表的 id 为主键,在 shops 表和 devices 表中的 customer_id 为外键,进行增减查删,返还给前端:[{id: #, shop: #, device: #}, {id: #, shop: #, device: #}] 格式的数据

之前写的代码如下:

Customers

  // 声明一个全局变量保存数据
  var CUSTOMER_DATA = []

var Customers = db.define(‘customers’, { id: Sequelize.INTEGER })

Shops

  var Shops = db.define('shops', {}, {
    classMethods: {

      // 根据customer_id和参数id匹配,计算Shops中匹配的总数
      countShop: function (id, callback) {
        Shops
          .count({
            where: {
               company_id: id
            }
          })
          .complete(function (num) {
          callback(num)
        })
      }  
    }
  })

//(Devices代码同Shops大同小异)

最终计算代码

  Customers
    .findAll()
    .complete(function (error, customers) {
      customers.each(function (customer) {
          var data = {}
          data.id = customer.dataValues.id
          // 根据data.id,计算shops数量
          Shops.countShop(data.id, function (num) {
            data.shop = num
            // 把格式正确的数据放到全局变量中,这里卡住了,异步的话怎么确定each执行完了然后暴露出来
            CUSTOMER_DATA.push(data)
           })
      })
    })

感谢任何有帮助的回答!


5 回复

当然可以。根据你的描述,你当前的实现方式使用了全局变量来存储结果,这不仅不利于代码的可维护性,还可能引入并发问题。我们可以使用 Sequelize 的关联功能来简化查询,并且通过 Promise 来处理异步操作。

首先,我们需要定义模型之间的关系。假设 customersshopsdevices 之间存在一对多的关系,我们可以这样定义模型:

const db = require('./db'); // 引入 Sequelize 实例

const Customer = db.define('customers', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  name: Sequelize.STRING // 假设有一个名称字段
});

const Shop = db.define('shops', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  customerId: {
    type: Sequelize.INTEGER,
    allowNull: false
  }
});

const Device = db.define('devices', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  customerId: {
    type: Sequelize.INTEGER,
    allowNull: false
  }
});

// 定义关联
Customer.hasMany(Shop, { foreignKey: 'customerId' });
Customer.hasMany(Device, { foreignKey: 'customerId' });

module.exports = {
  Customer,
  Shop,
  Device
};

接下来,我们可以通过 Sequelize 的关联方法来获取所需的数据。这里是一个示例代码,展示了如何获取每个客户的店铺和设备数量:

const { Customer, Shop, Device } = require('./models');

async function getCustomerData() {
  const customers = await Customer.findAll({
    include: [
      {
        model: Shop,
        attributes: []
      },
      {
        model: Device,
        attributes: []
      }
    ],
    attributes: ['id', [db.literal('(SELECT COUNT(*) FROM shops WHERE shops.customerId = customers.id)'), 'shopCount'], [db.literal('(SELECT COUNT(*) FROM devices WHERE devices.customerId = customers.id)'), 'deviceCount']]
  });

  return customers.map(customer => ({
    id: customer.id,
    shop: customer.shopCount,
    device: customer.deviceCount
  }));
}

getCustomerData().then(data => {
  console.log(data);
}).catch(err => {
  console.error(err);
});

在这个示例中,我们使用了 Sequelize 的 findAll 方法,并通过 include 选项将 ShopDevice 模型包含进来。为了计算每个客户的店铺和设备数量,我们使用了 db.literal 来执行子查询。最后,我们将结果映射成所需的格式。

这种方法避免了使用全局变量,并且通过 Promise 处理异步操作,使得代码更加清晰和易于维护。希望这对你有所帮助!


不明觉历

用Q

数组循环处理建议使用forEach

从你的描述来看,你希望通过 sequelizejs 实现对 customersshopsdevices 表的查询,并返回特定格式的数据。目前的实现方式遇到了异步问题,导致无法正确地收集所有结果。

下面是改进后的代码示例,使用 Promise.all 来处理异步操作:

改进后的代码

定义模型

const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('mysql://username:password@localhost:3306/database');

const Customers = sequelize.define('customers', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true
  }
});

const Shops = sequelize.define('shops', {
  customerId: {
    type: DataTypes.INTEGER,
    allowNull: false,
    references: {
      model: Customers,
      key: 'id'
    }
  }
});

const Devices = sequelize.define('devices', {
  customerId: {
    type: DataTypes.INTEGER,
    allowNull: false,
    references: {
      model: Customers,
      key: 'id'
    }
  }
});

查询并返回数据

async function getCustomerData() {
  const customers = await Customers.findAll();
  const customerPromises = customers.map(async (customer) => {
    const shopCount = await Shops.count({ where: { customerId: customer.id } });
    const deviceCount = await Devices.count({ where: { customerId: customer.id } });
    
    return {
      id: customer.id,
      shop: shopCount,
      device: deviceCount
    };
  });

  const customerData = await Promise.all(customerPromises);
  return customerData;
}

getCustomerData().then(data => {
  console.log(data); // [{id: #, shop: #, device: #}, {id: #, shop: #, device: #}]
}).catch(error => {
  console.error(error);
});

解释

  1. 定义模型:使用 Sequelize 定义 CustomersShopsDevices 模型,并设置外键关联。
  2. 查询函数:定义一个异步函数 getCustomerData,该函数首先获取所有的 Customers,然后对每个客户执行异步查询以统计其 ShopsDevices 的数量。
  3. 使用 Promise.all:将所有异步查询封装在一个数组中,并使用 Promise.all 等待所有查询完成。这样可以确保所有查询完成后才返回结果。
  4. 返回结果:最后返回格式化的数据。

这种方法避免了使用全局变量和回调地狱,使代码更加清晰和易于维护。

回到顶部