Normal Map is not displayed on Extruded SVG in THREE.js

The Normal Map, Roughness Map etc is not visible on the 3D Objects I extruded from an SVG. I have tested it with normal Box Geometrys and there it worked perfectly fine. Color, Opacity etc is also applied correctly on the Shapes.
Maybe its an issue with the UV map?

Hope someone can help.

Below is my code, if any of you needs more details just say so :).

import * as THREE from "three";

export async function createSCP() {
  const loader = new SVGLoader();
  const group = new THREE.Group();
  const groupSize = new THREE.Vector3();
  const glasSize = 40;
  const textureLoader = new THREE.TextureLoader();
  // SVG-Datei asynchron laden
  const data = await new Promise((resolve, reject) => {
    loader.load("/images/t_two.svg", resolve, undefined, reject);
  });

  const ceramicMaterial = createTexture(
    "ceramic_tiles",
    1,
    true,
    true,
    true,
    true,
    true,
    1,
    0.5,
    1,
    0
  );

  const material = new THREE.MeshStandardMaterial({
    color: 0x00affa,
    roughness: 1,
    normalMap: textureLoader.load(`/textures/plastic/normal.webp`),
  });

  material.normalScale.set(1, 1);

  material.roughnessMap = textureLoader.load(
    `/textures/plastic/roughness.webp`
  );

  const glassMaterial = new THREE.MeshPhysicalMaterial({
    color: 0xaaaaaa,
    roughness: 0,
    transmission: 1,
    thickness: 5,
    ior: 1.5,
    reflectivity: 0.5,
    clearcoat: 1,
    clearcoatRoughness: 0,
  });

  const paths = data.paths;

  for (const path of paths) {
    const shapes = path.toShapes(true);
    const tagName = path.userData.node.tagName.toLowerCase();

    for (const shape of shapes) {
      const scaledShape = scaleShape(shape, 1, glasSize);
      const geometry = new THREE.ExtrudeGeometry(
        tagName === "rect" ? scaledShape : shape,
        {
          depth: 10000,
          bevelEnabled: tagName === "rect",
          bevelSize: 8,
          UVGenerator: THREE.ExtrudeGeometry.WorldUVGenerator,
          bevelThickness: 2,
          bevelSegments: 1,
          bevelOffset: -8,
        }
      );

      // Plane-Mapping
      geometry.computeBoundingBox();
      const size = new THREE.Vector2(
        geometry.boundingBox.max.x - geometry.boundingBox.min.x,
        geometry.boundingBox.max.y - geometry.boundingBox.min.y
      );

      glassMaterial.roughness = 1;

      const mesh = new THREE.Mesh(
        geometry,
        tagName === "rect" ? material : ceramicMaterial
      );
      mesh.scale.set(0.001, 0.001, 0.001);
      mesh.castShadow = true;
      mesh.receiveShadow = true;
      mesh.rotateY(Math.PI / 2);
      mesh.updateMatrixWorld();

      const boundingBox = new THREE.Box3().setFromObject(mesh);
      boundingBox.getSize(size);

      if (tagName === "rect") {
        mesh.position.y -= size.y - size.y / glasSize;
      }

      group.add(mesh);
    }
  }

  // Gesamtgröße berechnen
  const boundingBox = new THREE.Box3().setFromObject(group);
  boundingBox.getSize(groupSize);

  // Mittig ausrichten
  group.rotation.set(0, Math.PI / 2, Math.PI);
  group.position.set(groupSize.z / 2, 0, -groupSize.x / 2);

  return group;
}

function scaleShape(shape, scaleX, scaleY) {
  const points = shape.getPoints();
  const scaledPoints = points.map(
    (p) => new THREE.Vector2(p.x * scaleX, p.y * scaleY)
  );
  return new THREE.Shape(scaledPoints);
}

JavaSript request in infinite loop stoped after few minutes

Im using the Javascript to read data from digital sensor connected to Raspbery PI (In this case – Rotary Encoder, but it’s not that important. This it could be anyone another sensor or controller).
In Raspbery PI launched the bash script which write sensor value in “encoder.php” file every time when sensor value is changed.
This code working perfectly:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="coords"></div>

<script>

async function fetchData() { 

 let response = await fetch("encoder.php");

 let text = await response.text();

  return new Promise(resolve => {
    setTimeout(() => resolve(text), 10);
  });
} 

async function myFunction() { 

  while (true) { 
    const data = await fetchData(); 
     document.getElementById("coords").innerHTML = data;
  } 
}

myFunction();

</script>

Every time then i’m rotate encoder – i’m see the sensor value in “coords” div.

But when i modify this code to (this switching the tabs on page depending on encoder direction):

<script>
async function fetchData() { 
  let response = await fetch("php/encoder.php");
 
  let text = await response.text();
 
   return new Promise(resolve => {
     setTimeout(() => resolve(text), 10);
   });
 } 
 
 async function myFunction() { 
 
   while (true) { 
     const data = await fetchData(); 
      resp = data;
     var readState = resp.substr(0,5);
     var direction = resp.substr(6);
     if (typeof lastState == 'undefined') {lastState = ""};
   //  console.log(direction);  
   //  console.log(readState);  
   // console.log(lastState);  
if (lastState != readState && lastState != "")
 {//console.log(direction)

     var test = document.getElementsByClassName("active")[0];  
    // console.log(test);  
     test2=test.innerHTML;
   //  console.log(test2);  
     var mySubString = test2.substr(10,6);
   //  console.log(mySubString);
     
     if (mySubString == "ST_NAV" && direction == "CCW")
      {
        
       document.getElementById("ST_SCREEN").classList.remove('active'); 
       document.getElementById("SE_SCREEN").classList.add('active');
       document.getElementById("ST_nav_el").classList.remove('active');
       document.getElementById("SE_nav_el").classList.add('active');
       document.getElementById("ST_NAV").classList.remove('active');
       document.getElementById("SE_NAV").classList.add('active');


      };

              
     if (mySubString == "ST_NAV" && direction == "CW")
      {

       document.getElementById("ST_SCREEN").classList.remove('active');
       document.getElementById("MA_SCREEN").classList.add('active');
       document.getElementById("ST_nav_el").classList.remove('active');
       document.getElementById("MA_nav_el").classList.add('active');
       document.getElementById("ST_NAV").classList.remove('active');
       document.getElementById("MA_NAV").classList.add('active');
       ShowMap();


      };

      if (mySubString == "SE_NAV" && direction == "CW")
      {
         

       document.getElementById("SE_SCREEN").classList.remove('active');
       document.getElementById("ST_SCREEN").classList.add('active');
       document.getElementById("SE_nav_el").classList.remove('active');
       document.getElementById("ST_nav_el").classList.add('active');
       document.getElementById("SE_NAV").classList.remove('active');
       document.getElementById("ST_NAV").classList.add('active');

      };

      if (mySubString == "MA_NAV" && direction == "CW")
      {
         

       document.getElementById("DA_SCREEN").classList.add('active');
       document.getElementById("MA_SCREEN").classList.remove('active');
       document.getElementById("DA_nav_el").classList.add('active');
       document.getElementById("MA_nav_el").classList.remove('active');
       document.getElementById("DA_NAV").classList.add('active');
       document.getElementById("MA_NAV").classList.remove('active');

      };

      if (mySubString == "MA_NAV" && direction == "CCW")
      {
         

       document.getElementById("ST_SCREEN").classList.add('active');
       document.getElementById("MA_SCREEN").classList.remove('active');
       document.getElementById("ST_nav_el").classList.add('active');
       document.getElementById("MA_nav_el").classList.remove('active');
       document.getElementById("ST_NAV").classList.add('active');
       document.getElementById("MA_NAV").classList.remove('active');

      };

      if (mySubString == "DA_NAV" && direction == "CCW")
      {
         

       document.getElementById("DA_SCREEN").classList.remove('active');
       document.getElementById("MA_SCREEN").classList.add('active');
       document.getElementById("DA_nav_el").classList.remove('active');
       document.getElementById("MA_nav_el").classList.add('active');
       document.getElementById("DA_NAV").classList.remove('active');
       document.getElementById("MA_NAV").classList.add('active');

      };

      if (mySubString == "DA_NAV" && direction == "CW")
      {
       document.getElementById("DA_SCREEN").classList.remove('active');
       document.getElementById("RA_SCREEN").classList.add('active');
       document.getElementById("DA_nav_el").classList.remove('active');
       document.getElementById("RA_nav_el").classList.add('active');
       document.getElementById("DA_NAV").classList.remove('active');
       document.getElementById("RA_NAV").classList.add('active');
      };

      if (mySubString == "RA_NAV" && direction == "CCW")
      {
       document.getElementById("DA_SCREEN").classList.add('active');
       document.getElementById("RA_SCREEN").classList.remove('active');
       document.getElementById("DA_nav_el").classList.add('active');
       document.getElementById("RA_nav_el").classList.remove('active');
       document.getElementById("DA_NAV").classList.add('active');
       document.getElementById("RA_NAV").classList.remove('active');
      }; 
 };
 lastState = readState;
   } 
 }
 
 myFunction();

</script>

Page normally functioning estimated 2-4 minutes, after this time switching between tabs doesn’t happen, as if the function is blocked or freeze. All other dynamic elements on page, continue to work. And page not reloading after pressing refresh or F5
The same if I try to open new tab and enter the page adress. Page not loaded until the tab with the non-working function is closed.

ExcelJS – How to get the current values of a dropdown of a cell

I’m populating an existing Excel file using ExcelJS.

Setting the value directly, without re-adding the dataValidation wipes out the dropdown. It’s necessary to re-add the validations again using the code below (for example):

const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(buffer);
const targetSheet = workbook.worksheets[1];
let row = targetSheet.getRow(rowNumber); // Target row
cell = row.getCell(4); // Target cell
cell.dataValidation = {
      type: 'list',
      allowBlank: false,
      formulae: ['"Option1,Option2,Option3"']
};

Now, I also need to read the existing dropdown values before setting the new value but using cell.dataValidation does not work to read the current dataValidation, but strangely it works to write them.

How to read the existing dataValidation of a specific cell using ExcelJS?

Why does `fs.writeFile` give “EBADF: bad file descriptor” when using `./`, but works with `/` in Node.js 22.14.0?

I’m encountering an issue with Node.js fs.writeFile when trying to write to a file using a relative path (./message.txt). Whenever I use ./, I get the error:

[Error: EBADF: bad file descriptor, write] {
  errno: -4083,
  code: 'EBADF',
  syscall: 'write'
}

However, if I use /message.txt, the file gets created in the root of my C drive (C:message.txt) without any issues. I’m using Node.js v22.14.0, and this problem persists even after ensuring the directory exists and using absolute paths. I suspect it could be related to Node.js handling of relative paths in this version. Has anyone else experienced this, or is there a workaround to reliably write files using a relative path?

What I Tried & Expected Behavior

  1. Reinstalling Node.js – Issue persists in v22.14.0.
  2. Using an absolute path (C:/Users/niran/Documents/message.txt) – Works fine.
  3. Using path.join(__dirname, "message.txt") – Still throws EBADF error.
  4. Ensuring the directory exists before writing – No change.
  5. Running the script as an administrator – No effect.

Here’s my latest attempt:

try {
  const fs = require("fs");
  const path = require("path");

  const filePath = path.join(__dirname, "message.txt");

  console.log(filePath);

  fs.readFile(filePath, "utf8", (err, data) => {
    if (err) {
      console.error(err);
      return;
    }
    console.log(data);
  });

  fs.writeFile(filePath, "Hello, Node.js", (err) => {
    if (err) {
      console.error(err);
      return;
    }
    console.log("The file has been saved!");
  });
} catch (error) {
  console.log(error);
}

What I Expected

I expected the file to be created in the same directory as my script, but instead, it throws EBADF.

Dropdown selection not populating an input field with the product price

I’m working on a Spring Boot + Thymeleaf project in which I have an order form. In that form, there is a dropdown for choosing a product, and I want the product’s price to automatically appear in the Net Unit Price input field right after the user selects an item from the dropdown.

I tried to store each product’s price in a data-price attribute on the elements, then used JavaScript to listen for a change event on the dropdown, grab the selected element’s data-price, and set that value in the input. However, no matter what I do, the Net Unit Price field remains blank. I even tested with plain HTML + JS, but it still doesn’t update in the live environment.

Here’s the relevant part of my Thymeleaf template:

    <select id="productSelect"
        th:field="*{product.id}"
        class="form-select"
        required>
    <option disabled selected value="">Select</option>
    <option th:each="p : ${products}"
            th:value="${p.id}"
            th:attr="data-price=${p.price}"
            th:text="${p.name}">
    </option>
</select>

<input type="number"
       step="0.01"
       th:field="*{netUnitPrice}"
       class="form-control"
       id="netUnitPrice"
       required />

<script>
    document.addEventListener('DOMContentLoaded', function() {
        const productSelect = document.getElementById('productSelect');
        const netPriceInput = document.getElementById('netUnitPrice');

        productSelect.addEventListener('change', function() {
            const selectedOption = this.options[this.selectedIndex];
            const price = selectedOption.getAttribute('data-price');
            if (price) {
                netPriceInput.value = price;
            }
        });
    });
</script>

I also have a base.html layout that loads Bootstrap and other scripts. I worried maybe it conflicts with my inline script, but I haven’t found a direct conflict. Right now, the JavaScript doesn’t throw any errors in the console, and the data-price attributes look correct in the rendered HTML, but the input never updates.

Any ideas on what I might be missing or doing wrong? Let me know if you need more details about the layout or the form. Thank you so much in advance!

Which JavaScript library that works alongside Drizzle ORM is better for pooling, pg, postgres or node-postgres?

I’m working on a JavaScript/TypeScript backend project using drizzle and PostgreSQL where I came across pooling for the first time. I found there are several ways to integrate pooling with drizzle ORM but they each rely on different libraries.

There is the pg/node-postgres method which goes like this:

import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL as string,
    max: 10
})

export const db = drizzle(pool, {
  schema: schema,
  logger: true,
});

And the Postgres.js version which goesl ike this:

import postgres from 'postgres';
import { drizzle } from 'drizzle-orm/postgres-js';

const client = postgres(process.env.DATABASE_URL as string, { max: 10 });
export const db = drizzle(client, {
  schema: schema,
  logger: true,
});

Is there a difference between these two methods? If so, which one is the better option?

Is console.log considered a side effect in JavaScript?

I was learning about side effects in JavaScript, and I came across the idea that console.log is considered a side effect. However, I’m not entirely sure why.

For example, in the following function:

function greet(name) {
    console.log("Hello, " + name); 
    return "Hello, " + name;
}

Since console.log does not modify any variables or return values, why is it classified as a side effect?

I tried using console.log inside a function and expected it to just display output without affecting the program’s logic. However, I read that logging is considered a side effect, and I’m trying to understand why

how to sorting array by multiple criteria

how to code sort array by criteria

  1. sort by risklevel.level high ==> abnormal ==> medium ===> low if have same level high look at count which array have more count come first

  2. if eaqul all level sort by name a-z

    [
    {
    risklevel: [
    {
    level: “high”,
    count: 5,
    },
    {
    level: “abnormal”,
    count: 2,
    },
    ],
    name: “bob”,
    },
    {
    risklevel: [
    {
    level: “high”,
    count: 2,
    },
    {
    level: “medium”,
    count: 1,
    },
    ],
    name: “adam”,
    },
    {
    risklevel: [
    {
    level: “low”,
    count: 1,
    },
    ],
    name: “ozzy”,
    },
    {
    risklevel: [
    {
    level: “low”,
    count: 8,
    },
    ],
    name: “ethan”,
    },
    {
    risklevel: [
    {
    level: “abnormal”,
    count: 6,
    },
    {
    level: “low”,
    count: 1,
    },
    ],
    name: “pam”,
    },
    {
    risklevel: [
    {
    level: “medium”,
    count: 10,
    },
    ],
    name: “cat”,
    },
    {
    risklevel: [
    {
    level: “medium”,
    count: 10,
    },
    ],
    name: “bee”,
    },
    {
    risklevel: [
    {
    level: “abnormal”,
    count: 20,
    },
    ],
    name: “tak”,
    },
    ];

result is

[
  {
    risklevel: [
      {
        level: "high",
        count: 5,
      },
      {
        level: "abnormal",
        count: 2,
      },
    ],
    name: "bob",
  },
  {
    risklevel: [
      {
        level: "high",
        count: 2,
      },
      {
        level: "medium",
        count: 1,
      },
    ],
    name: "adam",
  },
  {
    risklevel: [
      {
        level: "abnormal",
        count: 20,
      },
    ],
    name: "tak",
  },
  {
    risklevel: [
      {
        level: "abnormal",
        count: 6,
      },
      {
        level: "low",
        count: 1,
      },
    ],
    name: "pam",
  },
  {
    risklevel: [
      {
        level: "medium",
        count: 10,
      },
    ],
    name: "bee",
  },
  {
    risklevel: [
      {
        level: "medium",
        count: 10,
      },
    ],
    name: "cat",
  },
  {
    risklevel: [
      {
        level: "low",
        count: 8,
      },
    ],
    name: "ethan",
  },
  {
    risklevel: [
      {
        level: "low",
        count: 1,
      },
    ],
    name: "ozzy"  
  }
];


    

Use prettier to format Javascript code blocks in a FunnelWeb file

I have a FunnelWeb file whose @{...@} code blocks form a Javascript program. I want to use prettier to format these code blocks while leaving the non-code FunnelWeb source unchanged.

Here is my approach, my question is: are there better alternatives?

I have a Node.js program that processes the file line by line. Unless it is in “code block” state, it simply copies each line to the output. But:

  • If a line starts with a code block definition @$@<...@>@{, it outputs that line, creates a new “code buffer” and switches to “code block” state.
  • If it is in code block state, it adds the line to the code buffer.
  • If a line starts with @}, it leaves the “code block” state, processes the code buffer with prettier and outputs the resulting lines, followed by the current line.

The problem is that the @{...@} code block in the code buffer typically does not contain a Javascript program considered error-free by prettier. This is because FunnelWeb works by pasting code blocks together and into other code blocks without any regard to the programming language that they contain. In particular

  • a code block may contain @<...@> references to other code blocks
  • a code block often contains one method of a class and looks like
    method(args) {...}
    

    and prettier rejects this in the absence of the surrounding

    class Class {...}
    

To circumvent these two problems, my Node.js program

  • wraps @<...@> in comment syntax like /*@<...@>*/ before prettier formatting and unwraps them afterwards
  • converts an unindented method(args) { into function /*m*/ method(args) { before prettier formatting and converts it back afterwards
  • converts an unindented static method(args) { into function /*s*/ method(args) { before prettier formatting and converts it back afterwards.

The after-prettier processing thus performs

code = code
  .replaceAll("function /*s*/", "static")
  .replaceAll("function /*m*/ ", "")
  .replace(//*|*//g, "");

And if a code block still cannot be formatted by prettier, the unformatted code is output.

With this approach my only code blocks that cannot be formatted are one-liners like

ModuleName,

Again my question: Has anyone else tried this and found a better approach?

Background Service that keeps my app running in the background in react-native

I’m using react-native-android-notification-listener to listen to notifications from other apps. I want my app to listen to these notifications even when my app is closed from the recent applications. When i search for the solution, all i get are forground-services which runs the app in the foreground and persists a notification all the time. What I want is to run this application as a background-service.

Javascript to capture ONLY Closing of a tab/window of browser

Is there a way in Javascript to check ONLY for user Closing a tab/window of the browser?

window.onbeforeunload is very generic because it ALSO gets triggered when user hits F5 key for refresh, or when user clicks any <a href link or form submit.

Similarly, document.addEventListener('visibilitychange', is also very generic & it too gets triggered for all the above.

Checking for keyCode(116) like following code is specific to checking only when user hits F5 key:

function fkey(e) {

    if (e.keyCode == 116) {
        e.preventDefault();

        // do stuff...
    }
}

I am looking for similar (keyCode or any other alternatives), that can capture ONLY when user Closes a tab/window of the browser, not including other events like Refresh or link clicks.

PS: SO does not seem to have an answer for this. If any exist, let me know through comments & I’ll close this Q.

Javascript not working on mobile browser , however works on desktop

I have issue with javascript code not woking in mobile browser (android and ios). However, the same code

Below code basically is trying to fetch user location from ip addrees and then logs to aws dynamo db through aws lambda function url. Site is hosted on s3 as a static website
The below code works perfectly when i am running on my laptop browsers like chrome , Edge. However , on mobile browsers it is just not loading at all. just a blank scrren.

Earlier i just had modal code and it used to work both on mobile as well as on desktop browsers.

Is using addEventListener twice a problem or am i missing something?

Any pointers would be helpful.

const myModal = new bootstrap.Modal('#load-modal');

window.addEventListener('DOMContentLoaded',function () {
    myModal.show();    
});

 
document.addEventListener("DOMContentLoaded", function() {
    
    // Fetch latitude and longitude based on IP address
    fetch("https://ipapi.co/json")
        .then(response => response.json())
        .then(data => {
            console.log(data.latitude)
            console.log(data.longitude)
            const bdcAPI = `https://api-bdc.net/data/reverse-geocode-client?
                // latitude=${data.latitude}&
                // longitude=${data.longitude}`
        getAPI(bdcAPI)
        })
        .catch(error => {
            console.error("Error fetching IP address:", error);
        });
});

function getAPI(bdcAPI){
    fetch(bdcAPI)
    .then(response => response.json())
    .then(data => {
        console.log(data.countryName)
        console.log(data.city)
        
        functionURL(data.continentCode,data.continent,data.countryCode, 
            data.countryName,data.principalSubdivisionCode,data.principalSubdivision,data.city,data.locality)
    })
    .catch(error => {
        console.error("Error fetching country and city name", error);
    });
}

function functionURL(continentCode,continent,countryCode, countryName,
                    principalSubdivisionCode,principalSubdivision,city,locality){

    const functionurl = `aws lambda function url`

    console.log(functionurl)

    fetch(functionurl)
    .then(response => response.json())
    .then(data => {
        console.log('Location logged successfully!!')
    })
    .catch(error => {
        console.error("Error calling function url:", error);
    });
}

Set Windowing to label each idle session

I have a data set that goes in and out of idle and I want to give each idle session an id

{
    _id: ObjectId('67ba93d7f883e7c506027022'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T10:00:00.000Z'),
    status: 'active',
    location: { lat: 40.7128, lng: -74.006 },
    prev_status: null,
    prev_timestamp: null,
    new_idle_session: 1
  },
  {
    _id: ObjectId('67ba93d7f883e7c506027023'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T10:05:00.000Z'),
    status: 'idle',
    location: { lat: 40.713, lng: -74.007 },
    prev_status: 'active',
    prev_timestamp: ISODate('2025-02-22T10:00:00.000Z'),
    new_idle_session: 1
  },
  {
    _id: ObjectId('67ba93d7f883e7c506027024'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T10:10:00.000Z'),
    status: 'idle',
    location: { lat: 40.7135, lng: -74.008 },
    prev_status: 'idle',
    prev_timestamp: ISODate('2025-02-22T10:05:00.000Z'),
    new_idle_session: 0
  },
  {
    _id: ObjectId('67ba93d7f883e7c506027025'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T10:15:00.000Z'),
    status: 'idle',
    location: { lat: 40.714, lng: -74.009 },
    prev_status: 'idle',
    prev_timestamp: ISODate('2025-02-22T10:10:00.000Z'),
    new_idle_session: 0
  },
  {
    _id: ObjectId('67ba93d7f883e7c506027026'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T10:20:00.000Z'),
    status: 'active',
    location: { lat: 40.7145, lng: -74.01 },
    prev_status: 'idle',
    prev_timestamp: ISODate('2025-02-22T10:15:00.000Z'),
    new_idle_session: 0
  },
  {
    _id: ObjectId('67ba93d7f883e7c506027027'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T10:30:00.000Z'),
    status: 'idle',
    location: { lat: 40.715, lng: -74.011 },
    prev_status: 'active',
    prev_timestamp: ISODate('2025-02-22T10:20:00.000Z'),
    new_idle_session: 1
  },
  {
    _id: ObjectId('67ba93d7f883e7c506027028'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T10:40:00.000Z'),
    status: 'idle',
    location: { lat: 40.7155, lng: -74.012 },
    prev_status: 'idle',
    prev_timestamp: ISODate('2025-02-22T10:30:00.000Z'),
    new_idle_session: 0
  },
  {
    _id: ObjectId('67ba93d7f883e7c506027029'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T10:50:00.000Z'),
    status: 'active',
    location: { lat: 40.716, lng: -74.013 },
    prev_status: 'idle',
    prev_timestamp: ISODate('2025-02-22T10:40:00.000Z'),
    new_idle_session: 0
  },
  {
    _id: ObjectId('67ba93d7f883e7c50602702a'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T11:00:00.000Z'),
    status: 'idle',
    location: { lat: 40.7165, lng: -74.014 },
    prev_status: 'active',
    prev_timestamp: ISODate('2025-02-22T10:50:00.000Z'),
    new_idle_session: 1
  },
  {
    _id: ObjectId('67ba93d7f883e7c50602702b'),
    device_id: 'ABC123',
    timestamp: ISODate('2025-02-22T11:10:00.000Z'),
    status: 'idle',
    location: { lat: 40.717, lng: -74.015 },
    prev_status: 'idle',
    prev_timestamp: ISODate('2025-02-22T11:00:00.000Z'),
    new_idle_session: 0
  }
]

I would like every time a session id to be looking like this

  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T10:00:00.000Z"),
    "status": "active",
    "location": { "lat": 40.7128, "lng": -74.006 },
    "new_idle_session": 1,
    "idle_session_id": 1
  },
  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T10:05:00.000Z"),
    "status": "idle",
    "location": { "lat": 40.713, "lng": -74.007 },
    "new_idle_session": 1,
    "idle_session_id": 1
  },
  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T10:10:00.000Z"),
    "status": "idle",
    "location": { "lat": 40.7135, "lng": -74.008 },
    "new_idle_session": 0,
    "idle_session_id": 1
  },
  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T10:15:00.000Z"),
    "status": "idle",
    "location": { "lat": 40.714, "lng": -74.009 },
    "new_idle_session": 0,
    "idle_session_id": 1
  },
  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T10:20:00.000Z"),
    "status": "active",
    "location": { "lat": 40.7145, "lng": -74.01 },
    "new_idle_session": 0,
    "idle_session_id": 1
  },
  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T10:30:00.000Z"),
    "status": "idle",
    "location": { "lat": 40.715, "lng": -74.011 },
    "new_idle_session": 1,
    "idle_session_id": 2
  },
  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T10:40:00.000Z"),
    "status": "idle",
    "location": { "lat": 40.7155, "lng": -74.012 },
    "new_idle_session": 0,
    "idle_session_id": 2
  },
  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T10:50:00.000Z"),
    "status": "active",
    "location": { "lat": 40.716, "lng": -74.013 },
    "new_idle_session": 0,
    "idle_session_id": 2
  },
  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T11:00:00.000Z"),
    "status": "idle",
    "location": { "lat": 40.7165, "lng": -74.014 },
    "new_idle_session": 1,
    "idle_session_id": 3
  },
  {
    "device_id": "ABC123",
    "timestamp": ISODate("2025-02-22T11:10:00.000Z"),
    "status": "idle",
    "location": { "lat": 40.717, "lng": -74.015 },
    "new_idle_session": 0,
    "idle_session_id": 3
  }
]

And I used this but its setting it all to 4

      "$setWindowFields": {
        "partitionBy": "$device_id",
        "sortBy": { "timestamp": 1 },
        "output": {
          "idle_session_id": {
            "$sum": "$new_idle_session"
          }
        }
      }
    }

What can I partition by to get thie idle sessions that stay idle or end with idle to get numbered correctly from 1 to 3 versus all 4