在包含的包含上使用 where 子句对查询进行 Sequelize

xav*_*ard 10 sql node.js sequelize.js

我正在努力使用 sequelize 创建查询。

一些上下文

我有以下型号:

  • AManifestation可以有 [0..n]Event
  • AnEvent属于一个Manifestation(Event没有a就不能存在Manifestation)
  • APlace可以有 [0..n]Event
  • AnEvent属于一个Place(Event没有a就不能存在Place)
  • AManifestation可以有 [1..n]Place
  • APlace可以有 [0..n]Manifestation

我将关系建模如下:

Manifestation.hasMany(Event, { onDelete: 'CASCADE', hooks: true })
Event.belongsTo(Manifestation)

Place.hasMany(Event, { onDelete: 'CASCADE', hooks: true })
Event.belongsTo(Place)

Manifestation.belongsToMany(Place, { through: 'manifestation_place' })
Place.belongsToMany(Manifestation, { through: 'manifestation_place' })
Run Code Online (Sandbox Code Playgroud)

对我来说,这似乎相当正确,但如果您有意见,请不要犹豫。

问题

我正在尝试查询Place以获取所有Manifestation并Event发生在给定的Place. 但是对于Event那些,Manifestation即使Manifestation在给定的Place.

下面是我试图实现的“JSON”结构:

{
  id: 1,
  name: "Place Name",
  address: "Place address",
  latitude: 47.00000,
  longitude: -1.540000,
  manifestations: [
    {
      id: 10,
      title: "Manifestation one",
      placeId: 1,
      events: []
    },
    {
      id: 11,
      title: "Manifestation two",
      placeId: 3,
      events: [
        id: 5,
        title: "3333",
        manifestationId: 11,
        placeId: 1
      ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

所以我想包括Manifestationwith id: 11,因为它的一个Event出现在给定的Place(with id: 1)

更新 (04/06/20):现在我依靠 javascript 来获得预期的结果

我想如果我在询问之前发布我当前的解决方案会很好。

router.get('/test', async (req, res) => {
  try {
    const placesPromise = place.findAll()
    const manifestationsPromise = manifestation.findAll({
      include: [
        { model: event },
        {
          model: place,
          attributes: ['id'],
        },
      ],
    })

    const [places, untransformedManifestations] = await Promise.all([
      placesPromise,
      manifestationsPromise,
    ])

    const manifestations = untransformedManifestations.map(m => {
      const values = m.toJSON()
      const places = values.places.map(p => p.id)
      return { ...values, places }
    })

    const result = places
      .map(p => {
        const values = p.toJSON()
        const relatedManifestations = manifestations
          .filter(m => {
            const eventsPlaceId = m.events.map(e => e.placeId)
            return (
              m.places.includes(values.id) ||
              eventsPlaceId.includes(values.id)
            )
          })
          .map(m => {
            const filteredEvents = m.events.filter(
              e => e.placeId === values.id
            )
            return { ...m, events: filteredEvents }
          })
        return { ...values, manifestations: relatedManifestations }
      })
      .filter(p => p.manifestations.length)

    return res.status(200).json(result)
  } catch (err) {
    console.log(err)
    return res.status(500).send()
  }
})
Run Code Online (Sandbox Code Playgroud)

但我很确定我可以直接用 sequelize 做到这一点。任何想法或建议?

谢谢

Nil*_*noj 0

这不是最佳的。但你可以尝试一下:

const findPlace = (id) => {
    return new Promise(resolve => {
        db.Place.findOne({
            where: {
                id: id
            }
        }).then(place => {
            db.Manefestation.findAll({
                include: [{
                    model: db.Event,
                    where: {
                        placeId: id
                    }
                }]

            }).then(manifestations => {
                const out = Object.assign({}, {
                    id: place.id,
                    name: place.name,
                    address: place.address,
                    latitude: place.latitude,
                    longitude: place.longitude,
                    manifestations: manifestations.reduce((res, manifestation) => {
                        if (manifestation.placeId === place.id || manifestation.Event.length > 0) {
                            res.push({
                                id: manifestation.id,
                                title: manifestation.id,
                                placeId: manifestation.placeId,
                                events: manifestation.Event
                            })
                        }
                        return res;
                    }, [])
                })
            })
            resolve(out);
        })
    })
}
Run Code Online (Sandbox Code Playgroud)

由此,您可以获得分配给地点的所有表现或具有分配的任何事件。表现中包含的所有事件都分配给该地点。

编辑: 您也可以使用以下之一:

const findPlace = (id) => {
    return new Promise(resolve => {
        db.Place.findOne({
            include: [{
                model: db.Manefestation,
                include: [{
                    model: db.Event,
                    where: {
                        placeId: id
                    }
                }]

            }],
            where: {
                id: id
            }
        }).then(place => {
            db.Manefestation.findAll({
                include: [{
                    model: db.Event,
                    where: {
                        placeId: id
                    }
                }],
                where: {
                    placeId: {
                        $not: id
                    }
                }

            }).then(manifestations => {
                place.Manefestation = place.Manefestation.concat(manifestations.filter(m=>m.Event.length>0))
                resolve(place);// or you can rename, reassign keys here
            })
        })
    })
}
Run Code Online (Sandbox Code Playgroud)

这里我只取第一个查询中的直接表现。然后,不包含和连接的表现形式。