Maximus Decimus
Maximus Decimus

Reputation: 5261

How to filter by an array property in an array of objects

I have a collection initialized like this:

var invoices = new Array();
var invoice = new Invoice();
invoice.number = "123";
invoice.date = "2016-05-03";
invoice.amount = "100";
var products = new Products();

var product = new Product();
product.code = "A";
product.name = "bar";
products.push(product);   

var product2 = new Product();
product2.code = "B";
product2.name = "foo";
products.push(product2);

invoice.products = products;

Now I got to filter by the properties of the invoice like this.

var filtered = invoices.filter(function(invoice){
   return invoice.number == "123";
});

But now I want to get the invoice that matches with number and the product name

How can I do this

var filtered = invoices.filter(function(invoice){
   return invoice.number == "123" 
   // && invoice.products "name" == "foo";  //<-- At this level how can I filter?
});

Upvotes: 2

Views: 89

Answers (3)

Nick Messing
Nick Messing

Reputation: 504

If you want to obtain a new list of invoices with filtered products inside you need to clone invoices instead of linking them with filter:

    var filtered = []
    invoices.forEach(function (invoice) {
      if (invoice.number != "123") {
        return;
      }
      var newInvoice = new Invoice();
      newInvoice.number = invoice.number;
      newInvoice.date = invoice.date;
      newInvoice.amount = invoice.amount;
      var newProducts = invoice.products.filter(function (product) {
        return product.name == "foo"
      });
      newInvoice.products = newProducts
      filtered.push(newInvoice)
    });

UPD: as John said, if you want to filter invoices by the rule like: "Get all invoices that has number equal to 123 and has at least one product named "foo" this is the solution:

    var filtered = invoices.filter(function(invoice){
       return invoice.number == "123" && invoice.products.some(function (p) {
          return p.name == "foo";
       });
    });

Upvotes: 0

James Freund
James Freund

Reputation: 483

var filtered = invoices.filter(function(invoice){
   return invoice.number == "123" && invoice.products.some(function (p) {
      return p.name == "foo";
   });
});

Upvotes: 1

ShadowRanger
ShadowRanger

Reputation: 155363

Use Array.some to check for the presence of a product with the desired name:

var filtered = invoices.filter(function(invoice){
   return invoice.number == "123" && invoice.products.some(function(prod) {
       return prod.name === 'foo';
   });
});

Unlike using Array.filter and checking the length of the resulting array, this avoids creating a temporary array at all, and short-circuits; as soon as it finds a hit, it returns true immediately.

Upvotes: 6

Related Questions