skip to Main Content

I am working on an endpoint with nodejs/express and mongoose. The endpoint should return only the found ID like this:

{
    "id": 3000,
    "group": 3,
    "title": "",
    "start_time": "2023-07-31T11:00:00.000Z",
    "end_time": "2023-07-31T20:00:00.000Z",
    "category": "green"
}

However, when I tested (localhost:3000/api/one/3000) it returns all the values that belong to the users instead of just one:

{
    "_id": "658",
    "schedule": [
        {
            "events": [
                {
                    "id": 3000,
                    "group": 3,
                    "title": "",
                    "start_time": "2023-12-01T11:00:00.000Z",
                    "end_time": "2023-12-01T20:00:00.000Z",
                    "category": "green",
                },
                {
                    "id": 3001,
                    "group": 3,
                    "title": "",
                    "start_time": "2023-12-02T11:00:00.000Z",
                    "end_time": "2023-12-02T20:00:00.000Z",
                    "category": "green",
                },
                {
                    "id": 3002,
                    "group": 3,
                    "title": "",
                    "start_time": "2023-12-03T11:00:00.000Z",
                    "end_time": "2023-12-03T20:00:00.000Z",
                    "category": "green",
                },
                {
                    "id": 3003,
                    "group": 3,
                    "title": "",
                    "start_time": "2023-12-04T11:00:00.000Z",
                    "end_time": "2023-12-04T20:00:00.000Z",
                    "category": "green",
                },
                {
                    "id": 3004,
                    "group": 3,
                    "title": "",
                    "start_time": "2023-12-07T11:00:00.000Z",
                    "end_time": "2023-12-07T20:00:00.000Z",
                    "category": "green",
                }
]
        }
    ]
}

This is the mongo schema:

import mongoose, { model, Schema } from "mongoose";

const eventSchema = new mongoose.Schema({
  id: Number,
  group: Number,
  title: String,
  start_time: Date,
  end_time: Date,
  category: String,
});

const individualSchema = new mongoose.Schema({
  name: String,
  events: [eventSchema],
});

const ScheduleSchema = new mongoose.Schema({
  schedule: [individualSchema],
});

export default model("Schedule", ScheduleSchema);

This is the function which I think there is something missing on the findOne():

export const getById = async (req, res) => {
  try {
    const id = req.params.id;
    const found = await ScheduleSchema.findOne(
      { "schedule.events.id": id },
      { "schedule.events.$": 1 }
    );

    res.json(found);
  } catch (error) {
    console.log(error);
    console.error(error);
  }
};

how can I fix it so it only return the given id?

2

Answers


  1. I think based on your document design the best way would be to mock the findOne by using an aggregation and using the resulting object like so:

    export const getById = async (req, res) => {
       try {
          const id = req.params.id;
          const agg = await ScheduleModel.aggregate([
             {
                $match: {
                   "schedule.events.id": id
                }
             },
             {
                $unwind: "$schedule"
             },
             {
                 $unwind: "$schedule.events"
             },
             {
                $match: {
                   "schedule.events.id": id
                }
             },
             {
                $replaceRoot: {
                   newRoot: "$schedule.events"
                }
             }
          ]);
          const found = agg[0]; //< Use the 0 indexed object since aggregate returns an array.
    
          res.json(found);
       } catch (error) {
          console.log(error);
          console.error(error);
       }
    };
    

    See HERE for a working example of the aggregation.

    Note: for clarity I have used ScheduleModel as the name of your model to perform the query. Having the model named ScheduleSchema may be confusing to beginners using this answer in the future.

    Login or Signup to reply.
  2. You may like something with aggregation like this perhaps:

    db.collection.aggregate([
    {
     "$match": {
      "schedule.events.id": 3000
     }
    },
    {
    "$project": {
      "schedule": {
        "$map": {
          "input": "$schedule",
          "as": "s",
          "in": {
            "events": {
              "$filter": {
                "input": "$$s.events",
                "as": "e",
                "cond": {
                  "$eq": [
                    "$$e.id",
                    3000
                  ]
                }
              }
            }
          }
        }
       }
      }
     },
     {
     "$replaceRoot": {
       "newRoot": {
         $mergeObjects: "$schedule"
         }
        }
      },
      {
       "$replaceRoot": {
         "newRoot": {
          $mergeObjects: "$events"
        }
       }
      }
     ])
    

    Explained:

    1. Match the document having at least one nested object with id=3000
    2. map/filter only the matched nested object with id=3000
    3. flattent the object with 2x replaceRoot so you get just the nested object

    Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search