Retrieve the most recent date that has been sorted from various arrays

I currently have this data model:

var informationSchema = new Schema({
uid: { type: String },
sensors: [{
    nid: { type: String },
    cid: { type: String },
    details: {
        param1: { type: String },
        param2: { type: String },
        data: { type: String }
    },
    timestamp: { type: Date, default: Date.now }
}],
actuators: [{
    nid: { type: String },
    aid: { type: String },
    control_id: { type: String },
    details: {
        param1: { type: String },
        param2: { type: String },
        data: { type: String }
    },
    timestamp: { type: Date, default: Date.now }
}],
status: [{
    nid: {type: String},
    status_code: {type: String},
    date: { type: Date, default: Date.now }
}],
updated: { type: Date, default: Date.now },
created: { type: Date }
});

I am trying to create a query that fetches the latest entry from the "sensors," "actuators," and "status" arrays based on the provided "hid" value. The current approach I'm using retrieves one array at a time, requiring multiple database queries which is inefficient.

db.getCollection('data').aggregate([
                    { $match : { hid : "testhid" } },
                    {$project : {"sensors" : 1}},
                    {$unwind : "$sensors"},
                    {$sort : {"sensors.timestamp" : -1}},
                    {$limit : 1}
                ])

Any assistance would be greatly appreciated. Thank you.

Answer №1

One effective strategy is to ensure that the arrays are stored in a sorted manner from the beginning. It is likely that they are already sorted, especially since any $push operation (or even using .push()) will simply add items to the end of the array, making the latest item the "last" one by default.

If you are not altering the "date" properties after creation and the latest date is always the last item, then using $slice would be sufficient:

Data.find({ "hid": "testhid" }).select({
    "sensors": { "$slice": -1 },
    "actuators": { "$slice": -1 },
    "status": { "$slice": -1 }
}).exec(function(err,data) {

]);

If for some reason the data is not stored in date order, consider using the $sort modifier with $push to consistently sort additions to the arrays. You can update the entire collection in one statement:

Date.update(
    {},
    {
        "$push": {
            "sensors": { "$each": [], "$sort": { "date": 1 } },
            "actuators": { "$each": [], "$sort": { "date": 1 } },
            "status": { "$each": [], "$sort": { "date": 1 } }
        }
    },
    { "multi": true },
    function(err,num) {

    }
)

This statement ensures that each array in every document is re-sorted so that the latest date is the last entry. This makes using $slice as mentioned above appropriate.


If none of the previous methods apply and the data must be retrieved without being commonly stored in date order, only then resort to using .aggregate():

Data.aggregate([
    { "$match": { "hid": "testhid" } },
    { "$unwind": "$sensors" },
    { "$sort": { "_id": 1, "sensors.date": -1 } },
    { "$group": {
        "_id": "$_id",
        "sensors": { "$first": "$sensors" },
        "actuators": { "$first": "$actuators" },
        "status": { "$first": "$status" },
        "updated": { "$first": "$updated" },
        "created": { "$first": "$created" }
    }},
    { "$unwind": "$actuators" },
    { "$sort": { "_id": 1, "actuators.date": -1 } },
    { "$group": {
        "_id": "$_id",
        "sensors": { "$first": "$sensors" },
        "actuators": { "$first": "$actuators" },
        "status": { "$first": "$status" },
        "updated": { "$first": "$updated" },
        "created": { "$first": "$created" }
    }},
    { "$unwind": "$status" },
    { "$sort": { "_id": 1, "status.date": -1 } },
    { "$group": {
        "_id": "$_id",
        "sensors": { "$first": "$sensors" },
        "actuators": { "$first": "$actuators" },
        "status": { "$first": "$status" },
        "updated": { "$first": "$updated" },
        "created": { "$first": "$created" }
    }}
],
function(err,data) {

}
)

MongoDB does not have a direct way to sort array content inline in query results or aggregation pipelines. The method involves using $unwind, $sort, and $group with $first.

Each array needs to be processed separately due to $unwind creating separate documents for each array item. An alternative approach could involve combining all operations into one:

Data.aggregate([
    { "$match": { "hid": "testhid" } },
    { "$unwind": "$sensors" },
    { "$unwind": "$actuators" },
    { "$unwind": "$status" },
    { "$sort": { 
        "_id": 1, 
        "sensors.date": -1,
        "actuators.date": -1,
        "actuators.status": -1
    }},
    { "$group": {
        "_id": "$_id",
        "sensors": { "$first": "$sensors" },
        "actuators": { "$first": "$actuators" },
        "status": { "$first": "$status" },
        "updated": { "$first": "$updated" },
        "created": { "$first": "$created" }
    }}
],
function(err,data) {

}
)

Although it provides a combined approach, it may not offer significant improvement over the previously mentioned methods.


The key takeaway is to maintain sorted arrays and utilize $slice for simple retrieval of the latest item.

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

On the x-axis of the D3 graph, each data point is precisely the width of a date

I am currently trying to visualize data based on dates, and I am aiming for something similar to the following: My goal is to create rectangles that represent each day's data. Here is how I am drawing the rectangles: svg.selectAll(".my_class") .data ...

Experiencing an Internal Server Error while attempting to upload a product using AngularJS in the MEAN Stack

I'm currently struggling with an Internal Server error while trying to add a product through the http service ($http.post) in AngularJS. To provide you with the necessary details for assistance, here are the key files involved: **index.js : This file ...

Exploring plyr and vue.js: utilizing a computed property to fetch video duration

I am currently attempting to load content dynamically based on the duration of a video being displayed. However, I am encountering issues when trying to access the duration property. Could this problem be related to the timing of plyr's appearance wit ...

Can you explain the specific distinctions and pros/cons between the functions initializeUnorderedBulkOperation and initializeOrderedBulkOperation?

In my current Java project, I am tasked with implementing a BulkWriteOperation using MongoDB. During my research, I discovered two main types of BulkWriteOperations: initializeUnorderedBulkOperation() initializeOrderedBulkOperation() To learn more about ...

Using innerHTML in PHP to create a dynamic two-step echo effect

step 1: I am creating a form where input fields will be dynamically generated using innerHTML. var d = document.getElementById("d1p_1"); d.innerHTML += "<input class='add' name='field_" + i + "' type='text'>"; step 2: ...

When I attempt to dynamically insert a URL into the backgroundImage property using JSS in React with Material-UI, the image does not

If I want to statically display an image by importing it and using the variable in the useStyles function, I can do so like this: import React from 'react' import { makeStyles } from '@material-ui/core/styles' import { Box } from &apos ...

A straightforward Node.js function utilizing the `this` keyword

When running the code below in a Chrome window function test(){ console.log("function is " + this.test); } test(); The function test is added to the window object and displays as function is function test(){ console.log("function is " + this.tes ...

Utilizing Browser and Operating System Information as Body Class

In order to achieve pixel-perfect styling, I want to include the OS and browser information in the body class. This is necessary because fonts may appear differently depending on the OS/browser configuration. After some research and experimentation, I came ...

Key code problem - Struggling to block the entry of the % symbol

On my HTML page, I have an input text field that should only accept number keys and left/right arrow on the keyboard. I attempted to implement this using JavaScript, but encountered a problem. <input onkeypress="return allowNumberOnly(event)" /> fu ...

Is there a way to create a Captcha image from text using JavaScript in an HTML document?

As I work on creating a registration web page, ensuring security is key. That's why I'm looking for a way to generate captcha images for added protection. Any suggestions on how I can transform text into captcha images? ...

Is there a way to achieve horizontal alignment for the Twitter and Facebook buttons on my page?

By utilizing the html code provided, I successfully incorporated Twitter and Facebook "Like" buttons into my website. Initially, they were stacked vertically, which resulted in excessive use of vertical space. To optimize space usage, I decided to align th ...

Is there a way for me to retrieve the variables saved within this array in JavaScript (vue.js)?

I'm currently working on a project involving the JavaScript Vue.js Framework. I've encountered an issue that I need help with, and I've included some code below to illustrate my problem. In the code, I have two variables in the data section ...

I encountered an issue when trying to include the dotenv file, receiving the following error message: [TypeError: Network request failed]

babel.config.js File plugins: [ ["module:react-native-dotenv", { "envName": "APP_ENV", "moduleName": "@env", "path": ".env", "blocklist": null, "allowlist": null, "blacklist": null, // DEPRECATED "whitelist": ...

script for a background image that is centered and covers the entire screen

I have created a function to dynamically adjust the size of an image based on the window dimensions. However, there are times when the image does not fully expand to fill the width of the screen and instead remains constrained by its height. Any insights o ...

Mongoose fails to make updates

While working on a specific endpoint, I ran into an issue where the Mongoose library was not updating an entry as expected. export const playersTurn = async ( req: Request, res: Response, next: NextFunction ) => { try { [...] let symbol: ...

Checking for the presence of input element in jQuery after calling the remove() function

In my form, users can select predefined data and add new information in an input field called xxx before proceeding. When a user selects predefined data, a hidden input is generated dynamically. $('.selectlists').append('<input type="hi ...

Efficiently utilizing state in Redux

I encountered an issue with the following react redux code: The combined reducer looks like this const AllReducers = combineReducers({ foolow: follow_Reducer, vacations: vacations_Reducer, register: register_Reducer, ...

SMTPConnection._formatError experienced a connection timeout in Nodemailer

Our email server configuration using Nodemailer SMTP settings looked like this: host: example.host port: 25 pool: true maxConnections: 2 authMethod: 'PLAIN' auth: user: 'username' pass: 'pass' We encou ...

How can I replicate a div in Angular 6 using typescript?

I'm currently working on a project focused on providing detailed information about various vehicle components. Each component consists of specific descriptive fields. One feature I'm looking to implement is an "Add another component" button that ...

Is there a way to use Selenium to automate the clicking of two buttons with empty href attributes? Each button has a function name and arguments within the href

Here is the HTML code for both buttons: <td> <a href="javascript:abcMy(2310);" class="btn btn-lawa btn-primary btn-primary-lawa">View</a> </td> <td> <a href="javascript:abcMy(2330);" class="btn btn-lawa btn-primary btn ...