-1

I have a object that simulate a database relationships with multiple arrays and i want a sale that have a music genre (in this case, the sale with id: 1), but my code is returning all sales. I use the filter and map methods to simulate a select and join from SQL.

const db = {
  events: [
    {
      id: "1",
      name: "Rock in Rio 2020",
      genre: "Music",
    },
    {
      id: "2",
      nome: "World Cup 2022",
      genre: "Sport",
    },
  ],
  tickets: [
    {
      id: "1",
      eventId: "1",
      name: "Day 3",
      description: "Music Concert",
    },
    {
      id: "2",
      eventId: "1",
      name: "France x Brazil",
      description: "Football Match",
    },
  ],
  sales: [
    {
      id: "1",
      ticketId: "1",
      value: "100",
    },
    {
      id: "2",
      ticketId: "2",
      value: "200",
    },
  ],
};

const musicSales = db.sales.filter((sale) => {
  return db.tickets.map((ticket) => {
    return db.events.map((event) => {
      return (
        sale.ticketId === ticket.id &&
        event.id === ticket.eventId &&
        event.genre === "Music"
      );
    });
  });
});

console.log(musicSales);

Any idea how to fix this?

Thales Maia
  • 189
  • 5
  • [`Array#filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) expects a boolean to be returned, `true` if the iterated element should be kept, `false` if it should be passed over. You're returning an array which will always be truthy so everything will be kept. – pilchard Dec 30 '21 at 23:30
  • What result do you expect? – Mister Jojo Dec 30 '21 at 23:36
  • [{ "id": "1", "ticketId": "1", "value": "100" }] – Thales Maia Dec 30 '21 at 23:40
  • Why `db.tickets` elements have all the same `eventId` value ? – Mister Jojo Dec 30 '21 at 23:41

3 Answers3

1

If your intention is to retrieve a list of sales which have tickets for Music events, you could simply use filter and avoid the mapping.

For example

const musicSales = db.sales.filter((sale) => {
  const ticket = db.tickets[sale.ticketId];
  const event = db.events[ticket.eventId];
  return event.genre === "Music";
});

This filters the sales, looking up the ticket for each sale and the event for each ticket.

Note that this code assumes that every sale has a corresponding ticket and that every ticket has a corresponding event. If these assumptions don't hold, you'll need to add some if statements to check whether the tickets and events exist.

Jacob Brunson
  • 1,482
  • 4
  • 23
  • 37
  • I upvoted before I read this carefully. Those lookups on tickets and events should be done with find. As written, this assumes that the ids are indexes into the arrays. – danh Dec 30 '21 at 23:52
  • Yes, my post states these assumptions. – Jacob Brunson Dec 30 '21 at 23:53
  • No it states, that the objects *have ids*, which is a good assumption. But the code assumes that the *ids and the indexes in the arrays are the same*, which is an unstated assumption, and a bad one. – danh Dec 30 '21 at 23:55
  • 1
    Consider the difference between `const ticket = db.tickets[sale.ticketId];` and `const ticket = db.tickets.find(t => t.id === sale.ticketId);` – danh Dec 30 '21 at 23:56
  • Well, if we're being pedantic, it says "every sale has a corresponding ticket" which I take to mean "sale has an ticket ID" AND "ticket ID corresponds to a valid ticket". (Same for event). Since the question doesn't specify whether this assumption is relevant, I went with the simplest solution. – Jacob Brunson Dec 31 '21 at 02:20
  • Look at the OP's sale with `id:2`. It has `ticketId:2`. What is `db.tickets[2]`? **undefined**, because 2 is an out of bounds index. Your code fails when it tries to get the eventId property on undefined. – danh Dec 31 '21 at 02:38
0

You could try either of the following:

const musicSales = db.events.filter(event => event.genre == 'Music').map(event => db.sales.find(sale => sale.id == event.id));
OR
const musicSales = db.events.map(event => {
  if(event.genre == 'Music'){
    return db.sales.find(sale => sale.id == event.id);
  }
});.filter(Boolean);
Vektor
  • 697
  • 5
  • 14
0

I think you're trying to get all sales corresponding to a ticket with event ID 1?

If that's the case, you can do:

const musicSales db.sales.filter(sale => sale.ticketId in db.tickets.filter(ticket => ticket.eventId === "1"));

The tickets filter callback returns true if the ticket has eventId equal to "1".

The sales filter callback returns true if the sale has ticketId within the result of the tickets filter.

Eli Richardson
  • 934
  • 7
  • 25