Sort simple json based on an integer/string value

I’m not able to abstract away what I’m doing wrong here so I’m hoping for some help.

I’m using HTML extract > Set and then trying to sort the output > Sort according to https://docs.n8n.io/reference/javascript-code-snippets.html#_1-sort-items-based-on-an-integer-value, but I’m failing.

First, I get [HTML extract]

which I then [Set] into something useful as they need to be properly assigned to each other

Now, I see that at this stage I don’t have any “key” element to use the sort instruction on [neither on the number as a string or as a number, the HTML extract imports it as a string].

Just for completeness, here are the instructions for sorting from the documentation:

String sorting:

const sortedArr = items.sort((a, b) => {
    let a_name = a.json.name.toLowerCase(),
        b_name = b.json.name.toLowerCase();

    if (a_name < b_name) {
        return -1;
    }
    if (a_name > b_name) {
        return 1;
    }
    return 0;
});
return json:sortedArr;

Number sorting

const sortedArr = items.sort((a, b) => {
    return a.json.id - b.json.id;
})
return sortedArr;

Thanks a lot, I’m stuck so I’m happy about any guidance.

Welcome to the community. @somesimon

Do you to sort that object by what? the key or the values?

image

Hey Ricardo, thank you!

I’d like to filter by value.

p.s. noticed I have a date element there, which I’ve already removed, was an older screenshot.

ok, also what do you want to do with this information once is sorted by value? Depending on that it might also make sense to separated them in multiple items.

I’m interested to see both of these options tbh just to understand how I could manipulate it, but I really just need that:

  • these elements sorted by highest percent return descending
  • after I might write them to a Google sheet by the key to keep track of how they’ve changed

but yeh my first issue is to just sort it.

Check the example below:

{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "return [\n  {\n    json: {\n      \"DAI (Aave)\": '6.00010%',\n      \"sUSD (Aave)\": '9.3640%',\n    }\n  },\n]"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        510,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const results = [];\n\nfunction toFloat(element) {\n  return parseFloat(element.substring(0, element.length - 1))\n}\n\nfor (const item of items) {\n  const keysSorted = Object.keys(item.json).sort(function(a,b){ return toFloat(item.json[b]) - toFloat(item.json[a])})\n  const object = {};\n  for (const key of keysSorted) {\n    object[key] = item.json[key]\n  }\n  results.push({ json: object })\n}\n\nreturn results;\n"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        740,
        300
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Amazing, that works! I have so much to learn…

Unfortunately I think I still messed up my spec. This indeed allows me to add the info to a spreadsheet according to the column name (key), but I messed up on thinking through how to target and print the first 5 elements of that list, no matter the outcome of the sort and consequently the name of the key.

So for example I wanted to have in my formula something like .json[0] to pick to first element key and value out of the output, however I need to be more specific because of the setup {{$node["Sort/Filter by percent return"].json["3CRV (Harvest)"]}}

How should I rethink the process to basically filter by the value, but then pick the first (5) elements of the json by the value of content?

Am I making sense? I’m thinking whether I need to somehow redo that logic to merge the data into one key for every element [item = title + title modifier + content]

Thanks! Can’t wait to make it work

I do not think I understand :sweat_smile:

This is what I’m guessing.

1 - You are making an HTTP Request that is returning data about those crypto currencies.

2 - This HTTP is gonna be fire once a day? So you probably are using a Cron node

3 - You want to filter that data by value (DESC) and just pick the first 5?

4 - Take those 5 and save them in Google Sheets?

Can I see the structure the Google Sheets is gonna have? So I can have a better picture of what you want to achieve.

I thought I will be something with the headers like:

Date DAI (Aave) sUSD (Aave) etc
03/13/2021 6.0010% 9.3640%

But I’m not so sure anymore.

@RicardoE105! Damn I’m definitely failing, thanks for sticking with me.

Forget about the spreadsheet, I’m perfectly able to move the data to the spreadsheet for comparison reasons. I’m trying, however, to just output a selection of the elements into a simple tweet, by descending by the value (let’s say top 5).

The flow is:

  • scrape a table from a page / extract HTML [done]
  • from that I get title (currency name) / title modifier (source) / content (percentage) [done]
  • I’m using set to properly assign the values to the keys (this is the Sheets part) [done]
  • sort with your function [done]
  • output into, let’s say, a tweet, only the first 5 elements [struggling here]

Since I now have key : value I can’t really target it with the index .json[0*-4*].

"sUSD (Aave)": "9.0010%"
"USDC (Aave)": "6.7876%"
(...)

I’m not sure how to change the setup to get the top 5 elements from the json output into that tweet, without having to manually target them each time.

Desired output example:

Highest return:

:medal_sports: USD (Aave) - 9.0010%
:medal_sports: 2nd element from json sorted
:medal_sports: 3rd element from json sorted
:medal_military: 4th element from json sorted
:medal_military: 5th element from json sorted

More clear? :see_no_evil:

Now I get it. The example below should do it

{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "return [\n  {\n    json: {\n      \"DAI (Aave)\": '6.00010%',\n      \"sUSD (Aave)\": '9.3640%',\n    }\n  },\n]"
      },
      "name": "Function",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        490,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "const results = [];\n\nfunction toFloat(element) {\n  return parseFloat(element.substring(0, element.length - 1))\n}\n\nfor (const item of items) {\n  const keysSorted = Object.keys(item.json).sort(function(a,b){ return toFloat(item.json[b]) - toFloat(item.json[a])})\n  const object = {};\n  for (const key of keysSorted) {\n    object[key] = item.json[key]\n  }\n  results.push({ json: object })\n}\n\nreturn results;\n"
      },
      "name": "Function1",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        740,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "let i = 0\n\nconst lines = []\n\nconst medals = {\n  0: '🥇',\n  1: '🥈',\n  2: '🥉',\n  3: '🏅',\n  4: '🏅',\n}\n\nfor (const key of Object.keys(item)) {\n    if (i === 5) {\n      break;\n    }\n    lines.push(`${medals[i]}${key} - ${item[key]}`)\n    i++;\n}\n\n//Set the twitter like breaker here\nconst line_breaker = '\\n';\n\nconst tweet = lines.join(line_breaker)\n\nitem.tweet = tweet\n\nreturn item"
      },
      "name": "FunctionItem",
      "type": "n8n-nodes-base.functionItem",
      "typeVersion": 1,
      "position": [
        950,
        300
      ]
    }
  ],
  "connections": {
    "Start": {
      "main": [
        [
          {
            "node": "Function",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function": {
      "main": [
        [
          {
            "node": "Function1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function1": {
      "main": [
        [
          {
            "node": "FunctionItem",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
1 Like

thanks a bunch - can’t wait to test it out - unfortunately the n8n cloud is down since this morning. I’ll report back asap.

@RicardoE105, you are a magician and I hope to be like you one day. Incredible, I didn’t have this setup in mind but this works like a charm. <3

3 Likes

Hahaha glad that it worked. Let us know if you have any questions.

no seriously, it makes me super happy. Thanks again!

1 Like