Sequelize-Abfrage mit einer where-Klausel für ein Include eines Include

8

Ich habe Probleme, eine Abfrage mit Sequelize zu erstellen.

Ein Kontext

Ich habe folgende Modelle:

  • A Manifestationkann [0..n] habenEvent
  • Ein Eventgehört zu einem Manifestation(ein Eventkann ohne a nicht existierenManifestation )
  • A Placekann [0..n] habenEvent
  • Ein Eventgehört zu einem Place(ein Eventkann ohne a nicht existierenPlace )
  • A Manifestationkann [1..n] habenPlace
  • A Placekann [0..n] habenManifestation

Ich modelliere die Beziehungen wie folgt:

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' })

Für mich scheint es ziemlich richtig zu sein, aber zögern Sie nicht, wenn Sie Bemerkungen haben.

Die Frage

Ich versuche das abzufragen Place, um alles zu bekommen Manifestationund Eventin einem gegebenen zu geschehen Place. Aber für Eventdiejenigen möchte ich sie in ihre aufnehmen, Manifestationauch wenn das Manifestationnicht im Gegebenen passiertPlace .

Unten ist die "JSON" -Struktur, die ich erreichen möchte:

{
  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
      ]
    }
  ]
}

Also möchte ich das Manifestationmit id: 11 einschließen , weil eines davon Eventim Gegebenen vorkommt Place(mit id: 1)

Update (20.04.04): Im Moment verlasse ich mich auf Javascript, um das erwartete Ergebnis zu erhalten

Ich fand heraus, dass es schön wäre, wenn ich meine aktuelle Lösung veröffentlichen würde, bevor ich fragte.

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()
  }
})

Aber ich bin mir ziemlich sicher, dass ich das direkt mit Sequelize machen kann. Irgendwelche Ideen oder Empfehlungen?

Vielen Dank

xavier.seignard
quelle

Antworten:

0

Dies ist nicht optimal. Aber Sie können es ausprobieren:

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);
        })
    })
}

Daraus erhalten Sie alle Manifestationen, die dem Ort zugewiesen wurden oder die ein Ereignis zuweisen. Alle in den Manefestationen enthaltenen Ereignisse sind dem Ort zugeordnet.

Bearbeiten: Sie können auch das folgende verwenden:

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
            })
        })
    })
}

Hier nehme ich nur direkte Manifestationen in der ersten Abfrage. Dann Manifestationen, die nicht enthalten und verketten.

Nilanka Manoj
quelle
Vielen Dank für Ihre Antwort, das ist, was ich tatsächlich tue, und ich suchte nach einer Fortsetzung, um es zu tun, anstatt einer einfachen js.
xavier.seignard
Sie können jedoch
DB
Nachdem Sie sich Ihre Lösung angesehen haben, macht sie nicht das, wonach ich suche. Lesen Sie meine Frage noch
einmal
Entschuldigung, ich habe die Antwort jetzt bearbeitet
Nilanka Manoj
Die erste Antwort enthielt einige Tippfehler, die ich bearbeitet habe. Außerdem habe ich eine neue Antwort hinzugefügt
Nilanka Manoj