Jesus Jimenez
Jesus Jimenez

Reputation: 361

Sort array of objects by grouping properties

I have the following array of objects:

Update: full code

export const fetchInvoices = function (firestore, currentUser) {
    const db = firestore
        .collection("customers")
        .doc(currentUser)
        .collection("subscriptions");
    let invoices = [];
    db.get().then((subscriptionSnapshot) => {
        subscriptionSnapshot.forEach((doc) => {
            doc.ref.collection("invoices").get().then((invoiceSnapshot) => {
                invoiceSnapshot.forEach(async (doc) => {
                    let invoice = {
                        "billing_reason": doc.data().billing_reason,
                        "created": doc.data().created,
                        "currency": doc.data().currency,
                        "hosted_invoice_url": doc.data().hosted_invoice_url,
                        "id": doc.id,
                        "invoice_pdf": doc.data().invoice_pdf,
                        "number": doc.data().number,
                        "period_end": doc.data().period_end,
                        "period_start": doc.data().period_start,
                        "status": doc.data().status,
                        "subtotal": doc.data().subtotal,
                        "total": doc.data().total
                    };
                    Object.defineProperty(invoice, 'invoice_id', { value: doc.id });
                    invoices.push(invoice);
                })
            })
        });
    });
    const sortedData = invoices.sort((a, b) => +(b.status === 'open') - +(a.status === 'open'));
    console.log(sortedData);
    return sortedData;
}

I want to sort them by the ones with status: "open" on the first indexes, and then sort by created. Is there a way to do this?

I've been trying to sort only the group of status: "open" using Object.values(obj).includes("open") to determine if the object has the value and then sort by truth as here. But still can't even make this "sort by group".

Upvotes: 0

Views: 118

Answers (3)

pilchard
pilchard

Reputation: 12920

Sorting by two different criteria is simply a matter of chaining your criteria with logical OR (||).

In the first example, first by data.status converting boolean to an integer and then by data.created .

const data = [ { "created": 1, "status": "draft", }, { "created": 5, "status": "paid", }, { "created": 2, "status": "open", }, { "created": 6, "status": "paid", }, { "created": 3, "status": "open", }, { "created": 4, "status": "paid", }, ];

const sortedData = data
  .sort((a, b) => +(b.status === 'open') - +(a.status === 'open') || a.created - b.created);

console.log(sortedData);
.as-console-wrapper { max-height: 100% !important; top: 0; }

or, since you have multiple status values, you can create a sortOrder map and reference it in your sort callback.

const data = [ { "created": 1, "status": "draft", }, { "created": 5, "status": "paid", }, { "created": 2, "status": "open", }, { "created": 6, "status": "paid", }, { "created": 3, "status": "open", }, { "created": 4, "status": "paid", }, ];

const sortOrder = {
  open: 1,
  paid: 2,
  draft: 3
}

const sortedData = data
  .sort((a, b) => sortOrder[a.status] - sortOrder[b.status] || a.created - b.created);

console.log(sortedData);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

darrin
darrin

Reputation: 839

If you're open to using some great libraries out there this solution might work for you using underscore which is great for situations like this.

Assuming you put your original array into a variable called data as in Solvenc1no's answer :

    const _ = require('underscore');
    const sortedAndGrouped = _.groupBy(_.sortBy(data, "created"),'status');
    console.log(sortedAndGrouped);

Which results in this output:

{ draft:
   [ { billing_reason: 'subscription_create',
       created: 1614889156,
       currency: 'usd',
       hosted_invoice_url: '...',
       id: '...',
       invoice_pdf: '...',
       number: '82190D09-0001',
       period_end: 1614889156,
       period_start: 1614889156,
       status: 'draft',
       subtotal: 3900,
       total: 3900 } ],
  paid:
   [ { billing_reason: 'subscription_cycle',
       created: 1614890009,
       currency: 'usd',
       hosted_invoice_url: '...',
       id: '...',
       invoice_pdf: '...',
       number: '82190D09-0002',
       period_end: 1614890009,
       period_start: 1614890009,
       status: 'paid',
       subtotal: 3900,
       total: 3900 },
     { billing_reason: 'subscription_create',
       created: 1614890802,
       currency: 'usd',
       hosted_invoice_url: '...',
       id: '...',
       invoice_pdf: '...',
       number: '82190D09-0004',
       period_end: 1614890802,
       period_start: 1614890802,
       status: 'paid',
       subtotal: 3900,
       total: 3900 },
     { billing_reason: 'subscription_create',
       created: 1614892003,
       currency: 'usd',
       hosted_invoice_url: '...',
       id: '...',
       invoice_pdf: '...',
       number: '82190D09-0005',
       period_end: 1614892002,
       period_start: 1614892002,
       status: 'paid',
       subtotal: 3900,
       total: 3900 },
     { billing_reason: 'subscription_create',
       created: 1614893124,
       currency: 'usd',
       hosted_invoice_url: '...',
       id: '...',
       invoice_pdf: '...',
       number: '82190D09-0006',
       period_end: 1614893124,
       period_start: 1614893124,
       status: 'paid',
       subtotal: 3900,
       total: 3900 } ],
  open:
   [ { billing_reason: 'subscription_update',
       created: 1614890064,
       currency: 'usd',
       hosted_invoice_url: '...',
       id: '...',
       invoice_pdf: '...',
       number: '82190D09-0003',
       period_end: 1614890064,
       period_start: 1614890009,
       status: 'open',
       subtotal: -1400,
       total: -1400 } ] }

Upvotes: 0

timbersaw
timbersaw

Reputation: 660

You can get objects with open status using filter method and sort them using sort method like this.

You can change the order of sort by returning value accordingly in sort function.

const data = [
    {
        "billing_reason": "subscription_create",
        "created": 1614889156,
        "currency": "usd",
        "hosted_invoice_url": "...",
        "id": "...",
        "invoice_pdf": "...",
        "number": "82190D09-0001",
        "period_end": 1614889156,
        "period_start": 1614889156,
        "status": "draft",
        "subtotal": 3900,
        "total": 3900
    },
    {
        "billing_reason": "subscription_cycle",
        "created": 1614890009,
        "currency": "usd",
        "hosted_invoice_url": "...",
        "id": "...",
        "invoice_pdf": "...",
        "number": "82190D09-0002",
        "period_end": 1614890009,
        "period_start": 1614890009,
        "status": "paid",
        "subtotal": 3900,
        "total": 3900
    },
    {
        "billing_reason": "subscription_update",
        "created": 1614890064,
        "currency": "usd",
        "hosted_invoice_url": "...",
        "id": "...",
        "invoice_pdf": "...",
        "number": "82190D09-0003",
        "period_end": 1614890064,
        "period_start": 1614890009,
        "status": "open",
        "subtotal": -1400,
        "total": -1400
    },
    {
        "billing_reason": "subscription_create",
        "created": 1614890802,
        "currency": "usd",
        "hosted_invoice_url": "...",
        "id": "...",
        "invoice_pdf": "...",
        "number": "82190D09-0004",
        "period_end": 1614890802,
        "period_start": 1614890802,
        "status": "paid",
        "subtotal": 3900,
        "total": 3900
    },
    {
        "billing_reason": "subscription_create",
        "created": 1614892003,
        "currency": "usd",
        "hosted_invoice_url": "...",
        "id": "...",
        "invoice_pdf": "...",
        "number": "82190D09-0005",
        "period_end": 1614892002,
        "period_start": 1614892002,
        "status": "paid",
        "subtotal": 3900,
        "total": 3900
    },
    {
        "billing_reason": "subscription_create",
        "created": 1614893124,
        "currency": "usd",
        "hosted_invoice_url": "...",
        "id": "...",
        "invoice_pdf": "...",
        "number": "82190D09-0006",
        "period_end": 1614893124,
        "period_start": 1614893124,
        "status": "paid",
        "subtotal": 3900,
        "total": 3900
    },
    
]

const open = data.filter(d => d.status === "open").sort((a,b) => a.created - b.created);

console.log(open);

Upvotes: 0

Related Questions