Loop through a JSON object in JavaScript, merging dates and times based on their order of occurrence

I have been diving into a solution inspired by the discussion in this thread, but I am facing a roadblock when it comes to handling the formatting disparity between my JSON data and the example provided. It could be that this challenge is simpler than I perceive it to be; any guidance or references pointing me in the right direction would be greatly appreciated.

UPDATE: The JSON structure I'm dealing with looks like this:

[{"test":{"field1":"test123"},"info""2021-10-04\nPage visit 09:57:33\n - URL: https://www.google.com/\nPage visit 09:57:50\n - URL: https://www.google.com/blah-blah-blah/\nPage visit 09:56:03\n - URL: https://google.com/random-text/blah/\n\n2021-11-04\nPage visit 13:46:03\n - URL: https://www.google.com/blah/blah-blah/\n\n"}]

My aim is to parse through this data string, extract each URL, date, and timestamp, combine the dates and timestamps into a unified "yyyy-mm-dd 00:00:00" datetime format (e.g., "2021-10-04 08:57:23"), and then store these combined datetime values along with their corresponding URLs in a two-column array.

Although I can isolate the URLs and dates using regex, the challenge lies in pairing up the correct timestamps with their respective dates since they are listed separately.

//Extract URLs, dates, times
const urlMatches = text.match(/\bhttps?:\/\/\S+/gi);
const dateMatches = text.match(/(\d{1,4}([.\-/])\d{1,2}([.\-/])\d{1,4})/g);
const timeMatches = text.match(/\d{1,2}\D\d{1,2}\D(\d{4}|\d{2})/g);

Answer №1

Utilize functions like map and reduce, although it's uncertain if they offer better readability compared to the straightforward forEach method. Remove those line breaks with a different delimiter for improved clarity. While optional, this will simplify the process. Then employ a regex such as p1 to segment it into date clusters. Take note of the clear indicator of a double line break. Leverage matchAll along with spreading to transform it into an array.

Go through that array step by step. With the assistance of the initial capturing group, the date resides in the first position. Save the date in a variable, then apply a secondary regex to isolate the time/URL pairs (from the second capturing group), subsequently iterating through them to combine with the stored date value.

const data = {
  "info": [
    "2021-10-04\nPage visit 09:57:33\n - URL: https://www.google.com/\nPage visit 09:57:50\n - URL: https://www.google.com/blah-blah-blah/\nPage visit 09:56:03\n - URL: https://google.com/random-text/blah/\n\n2021-11-04\nPage visit 13:46:03\n - URL: https://www.google.com/blah/blah-blah/\n\n"
  ]
};

const text = data.info[0];
const p1 = /(\d{4}-\d{2}-\d{2})~(.*?)~~/g;
let vals = [...text.replaceAll("\n", "~").matchAll(p1)];

const p2 = /page visit\s+([^~]*)~\s+-\s+url:\s+([^~]*)/ig;
let buffer = [];

vals.forEach(v=>{
  let t = v[1];
  let parsed = [...v[2].matchAll(p2)];
  parsed.forEach(p=>{
    buffer.push({dt: t, time: p[1], url: p[2]});  
  });
});

console.log(buffer);

If the date groups are delimited by a double line break and the date itself is succeeded by a single line break, then the initial pattern can be streamlined, for instance: /([^~]*)~(.*?)~~/g. It's worth noting that the ~~ terminator only functions effectively if the last date is trailed by a double line break, which appears to be the case. Should that not be true, consider using something like (?:~~)? instead of just ~~.

Answer №2

To begin with, you can divide the lengthy string using the .split() method by separating it at each line break ("\n"). After that, employing the .reduce() function on the divided array allows for various manipulations such as matching, conversion to dates, and more.

Answer №3

To achieve the desired outcome, you can utilize a combination of the .split(), .map(), and .reduce() methods in the following manner:

const data = jsonData.info.map(line =>
    line.split(/[\n]{2,}/)
        .filter(l => l)
        .map(ln => ln.split(/(?:\n| - |URL: |Page visit )+/)
            .filter(v => v)
            .map(arr => arr.slice(1).reduce((acc, cur, i, ar) => i % 2 === 0 ? [...acc, ar.slice(i, i + 2)] : acc, [])
                .map(([time, url]) => ({
                    timestamp: `${arr[0]} ${time}`,
                    url
                }))
            )
        )
        .flat()
);

DEMO

const jsonData = {
  "info": [
    "2021-10-04\nPage visit 09:57:33\n - URL: https://www.google.com/\nPage visit 09:57:50\n - URL: https://www.google.com/blah-blah-blah/\nPage visit 09:56:03\n - URL: https://google.com/random-text/blah/\n\n2021-11-04\nPage visit 13:46:03\n - URL: https://www.google.com/blah/blah-blah/\n\n"
  ]
}

const data = jsonData.info.map(line => 
    line.split(/[\n]{2,}/)
        .filter(l => l)
        .map(ln => ln.split(/(?:\n| - |URL: |Page visit )+/)
            .filter(v => v)
            .map(arr => arr.slice(1).reduce((acc,cur,i,ar) => i%2 === 0 ?[...acc,ar.slice(i,i+2)] : acc,[])
                .map(([time, url]) => ({timestamp:`${arr[0]} ${time}`,url}))
            )
        )
        .flat()
);

console.log( data );

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Specialized serializer and deserializer utilizing GSON for a collection of BasicNameValuePairs

Struggling to create a custom Gson serializer and deserializer for a list of BasicNameValuePair objects. Found some helpful code snippets for serialization here. Decided to tackle deserialization as well, so here's my attempt: package dto; import ...

What causes alterations in a single cell to spread to adjacent cells within this 2D array initialized using the fill function?

I seem to be encountering an issue with this 2-dimensional array in JavaScript. It appears that when I modify a[1][0], the value of a[0][0] also changes. Could it be a problem with how I am initializing it? If so, what is the correct way to initialize it ...

Manipulating the DOM with Javascript and jQuery: Adding a new element and retrieving its reference

I am encountering an issue with a Web App that relies on JavaScript and jQuery. Essentially, the website includes a button that triggers a JavaScript function when clicked. Within this function, there are two other functions named Foo and Bar. Foo generate ...

Guide to displaying a canvas as an image in a new tab using Reactjs

My current project involves using a canvas barcode generated by the react-barcode library. At the moment, I can only right-click on the canvas to open it as an image in a new tab. Is there a way to achieve this functionality with just a click of a button i ...

Creating a dynamic column template that displays and checks checkboxes conditionally

I am faced with the task of dynamically generating columns on a screen based on values retrieved from a database. I have successfully created Kendo grid columns based on this input. However, these columns need to display checkboxes that are conditionally ...

Alter the truth value of an item contained within an array

Embarking on my JavaScript journey, so please bear with me as I'm just getting started :) I am working on a small app where the images on the left side are stored in an array. When a user clicks on one of them, I want to change its height and also tog ...

Hold off on transmitting information until all Promises have been fulfilled

I'm facing an issue where I need to query my database twice, log the data, and then send it. However, due to the promise not resolving in time, I am unable to send the data promptly. Can someone advise me on how to ensure that all promises are resolve ...

Access data from a multi-dimensional array with the help of a variable

I am attempting to extract keys and values from a multi-dimensional array dynamically. To illustrate my goal, please refer to the following code snippet: $i = 0; foreach ($faq as $f) { $q = 'faq'.$i; $a = 'faq'.$i.'_answer ...

Slow execution of Bootstrap v4 modal display

It has come to my attention that the modals in Bootstrap show slower as the page's content increases. When the page is empty, it only takes less than 100ms to show. However, the time it takes significantly increases as more content is added to the pa ...

"Trouble ensues when OrbitControls fail to function properly while loading a

I have a code snippet that displays a 3D file (obj, stl, 3mf) uploaded by the user using three.js OBJLoader, STLLoader, and 3MFLoader. Everything seems to be working fine, but I attempted to integrate OrbitControls so users can zoom in, zoom out, rotate, e ...

Assignment: Creating a pointer-based array

I'm currently working on a homework problem and have encountered an issue. A few of my classmates and I believe that our teacher may have misspoken. I've searched through various resources but haven't found a way to use pointers to essential ...

How to extract information for divs with specific attribute values using Jquery

I have multiple divs with IDs like #result-1, #result-2, each followed by a prefix number. To count the number of list items within these divs, I use the following code: $(document).ready(function () { var colorCount = $('#result-1 .item-result ...

Is there a way to convert NuGet.NuGetVersion to a class in C# through deserialization?

As a novice programmer working on an application for my job, I recently encountered an issue while trying to deserialize a class. The class in question is named Nuget, and its structure is as follows: public class Nuget { public string? Name { get; set ...

Sending data via an AJAX POST request in the request parameter

I have a question regarding the method of making a POST request in my code: $.ajax({ url :"/clientCredentials.json", type: "POST", data: { "clientEmail": email, "clientName":clientName, "orgName":orgName, "l ...

Which Jackson versions are compatible with the JBoss 6.4.20 patch?

Looking to upgrade my Jackson version following the JBoss patch 6.4.20. Using org.codehause.jackson, and it seems JBoss 6.4.x doesn't supply implicit dependencies for the newer com.fasterxml.jackson. Wondering if jackson-mapper-asl-1.9.9.redhat-6 is ...

How can I show a dynamic popover with specific content when a "Copy" action is triggered?

I am attempting to copy a value to the clipboard: /** * If the browser does not support direct clipboard manipulation, use an alternate method * This is used in the copyTextToClipboard function. * * Function found at: https://stackoverflow.com/a/3 ...

Rediscovering the Depths of Nested JSON Arrays in Postgres

I've been diligently searching for a solution to this specific issue, but unfortunately, I haven't come across anything that aligns closely with what I'm seeking. Within my database, I have two distinct tables: CREATE TABLE skill_tree ( ...

Saving User Identification on Client-Side Application to Make API Requests

Currently, I have a Node-Express REST API that allows for making a GET request to a user controller - /users/:id. The user-id number is stored in the database. Additionally, there is a React-Redux client-side app that communicates with the API. To make thi ...

Is there a way to verify the textbox value in MVC without the need for clicking submit or performing a postback

Exploring MVC for the first time. I am working on a Registration Form with 10 textboxes for id, name, address, etc. I need to validate if the entered Id is already in the database and display the status without requiring the user to click a submit button. ...

Retrieve items from an array using a series of nested map operations

When I execute the query below, it transforms the json data into objects - 1st level being a map (This works fine as expected) const customerOptions = () => { return customersQuery.edges.map(({ node: { id, name } }) => { return { key: id, text ...