0

I have collection Label like this:

{
    "_id" : ObjectId("6234364c406b5e0bd4f9bb1b"),
    "is_deleted" : false,
    "labelName" : "cats",
    "description" : "cats ",
    "datasetId" : ObjectId("62343589f8afb4001e27a00c"),
    "createdAt" : ISODate("2022-03-18T07:35:40.622Z"),
    "updatedAt" : ISODate("2022-03-18T07:35:40.622Z"),
    "__v" : 0
}

Below is Image collection:

{
    "_id" : ObjectId("62382d400c0082003122a12b"),
    "is_deleted" : false,
    "labels" : [ 
        {
            "_id" : ObjectId("623d76c55ecb9849943020ab"),
            "labelId" : ObjectId("6234364c406b5e0bd4f9bb1b"),
            "xmax" : 10,
            "xmin" : 20,
            "ymax" : 20,
            "ymin" : 20
        }
    ],
    "img_name" : "6911578680130170881655.jpg",
    "img_originalname" : "cats_00001.jpg",
    "img_desc" : "Cyber Sercurity multi upload",
    "img_uri" : "http://localhost:4031/resources/images/2022/3/21/6911578680130170881655.jpg",
    "img_path" : "/resources/images/2022/3/21/6911578680130170881655.jpg",
    "datasetId" : ObjectId("62382d400c0082003122a0e8"),
    "createdAt" : ISODate("2022-03-21T07:46:08.431Z"),
    "updatedAt" : ISODate("2022-03-25T08:01:09.993Z"),
    "__v" : 0
}

And this is how I organize the "Image" model in mongoose to query data in NodeJS:

const mongoose = require("mongoose");

const ImageSchema = mongoose.model("Image",
    new mongoose.Schema({
        img_name: String,
        img_originalname: String,
        img_uri: String,
        img_desc: String,
        img_path: String,
        img_destination: String,
        img_width: Number,
        img_height: Number,
        datasetId: {type: mongoose.Schema.Types.ObjectId, ref: "Dataset"},
        datanoiseId: {type: mongoose.Schema.Types.ObjectId, ref: "Datanoise"},
        labels: [{
            labelId:{type: mongoose.Schema.ObjectId, ref: 'Label'},
            xmax: Number,
            xmin: Number,
            ymax: Number,
            ymin: Number,
        }],
        is_deleted: { type: Boolean, default: false, select: false }
    }, {
        timestamps: true,
        collection: 'Image'
    })
);

module.exports = ImageSchema;

The "labels" field is an array of the "Image" collection, this field is null when the image is unlabeled, but after the image is labeled it is an array consisting of elements as following: labelId is a reference to Collection "Label", the parameters xmax, xmin, ymax, ymix are the coordinates surrounding the labeled area.

Now I want to filter all the images with label by the available labelId, how do I do that? I just try follow this issue but not worked,

https://stackoverflow.com/questions/63368225/mongoose-find-documents-if-array-contains-a-value

I think that because my problem is specifically about labeling and surrounding coordinates, I organize the data a little differently.

Currently when I query like this:

http://localhost:8080/backend/api/image?count=1&lskip=60&limit=5&datasetId=62343589f8afb4001e27a00c

So the result is bellow:

{
    "data": [
        {
            "_id": "62380153f18897001e31f63c",
            "labels": [
                {
                    "labelId": {
                        "_id": "6234364c406b5e0bd4f9bb1b",
                        "labelName": "cats",
                        "description": "cats ",
                        "datasetId": "62343589f8afb4001e27a00c",
                        "createdAt": "2022-03-18T07:35:40.622Z",
                        "updatedAt": "2022-03-18T07:35:40.622Z",
                        "__v": 0
                    }
                }
            ],
            "img_name": "6911531514657402880.jpg",
            "img_originalname": "cats_00001.jpg",
            "img_desc": "Cyber Sercurity multi upload",
            "img_uri": "http://localhost:8080/resources/images/2022/3/21/6911531514657402880.jpg",
            "img_path": "/resources/images/2022/3/21/6911531514657402880.jpg",
            "datasetId": {
                "dataset_type": "classification",
                "_id": "62343589f8afb4001e27a00c",
                "dataset_name": "Bộ dữ liệu dev model",
                "dataset_status": "Đồng bộ",
                "description": "Bộ dữ liệu gồm chó mèo gấu"
            },
            "createdAt": "2022-03-21T04:38:43.150Z",
            "updatedAt": "2022-03-21T04:38:43.150Z",
            "__v": 0
        },
        {
            "_id": "62380143f18897001e31f61e",
            "labels": [
                {
                    "labelId": {
                        "_id": "6234364c406b5e0bd4f9bb1b",
                        "labelName": "cats",
                        "description": "cats ",
                        "datasetId": "62343589f8afb4001e27a00c",
                        "createdAt": "2022-03-18T07:35:40.622Z",
                        "updatedAt": "2022-03-18T07:35:40.622Z",
                        "__v": 0
                    }
                }
            ],
            "img_name": "6911531447200411648.jpg",
            "img_originalname": "cats_00012.jpg",
            "img_desc": "Cyber Sercurity multi upload",
            "img_uri": "http://localhost:8080/resources/images/2022/3/21/6911531447200411648.jpg",
            "img_path": "/resources/images/2022/3/21/6911531447200411648.jpg",
            "datasetId": {
                "dataset_type": "classification",
                "_id": "62343589f8afb4001e27a00c",
                "dataset_name": "Bộ dữ liệu dev model",
                "dataset_status": "Đồng bộ",
                "description": "Bộ dữ liệu gồm chó mèo gấu"
            },
            "createdAt": "2022-03-21T04:38:27.072Z",
            "updatedAt": "2022-03-21T04:38:27.072Z",
            "__v": 0
        },
        {
            "_id": "62343589f8afb4001e27a04f",
            "labels": [
                {
                    "labelId": {
                        "_id": "6234364c406b5e0bd4f9bb1b",
                        "labelName": "cats",
                        "description": "cats ",
                        "datasetId": "62343589f8afb4001e27a00c",
                        "createdAt": "2022-03-18T07:35:40.622Z",
                        "updatedAt": "2022-03-18T07:35:40.622Z",
                        "__v": 0
                    }
                }
            ],
            "img_name": "6910488063828455425.jpg",
            "img_originalname": "cats_00001.jpg",
            "img_desc": "Cyber Sercurity multi upload",
            "img_uri": "http://localhost:8080/resources/images/2022/3/18/6910488063828455425.jpg",
            "img_path": "/resources/images/2022/3/18/6910488063828455425.jpg",
            "datasetId": {
                "dataset_type": "classification",
                "_id": "62343589f8afb4001e27a00c",
                "dataset_name": "Bộ dữ liệu dev model",
                "dataset_status": "Đồng bộ",
                "description": "Bộ dữ liệu gồm chó mèo gấu"
            },
            "createdAt": "2022-03-18T07:32:25.200Z",
            "updatedAt": "2022-03-18T07:32:25.200Z",
            "__v": 0
        },
        {
            "_id": "62343589f8afb4001e27a04e",
            "labels": [
                {
                    "labelId": {
                        "_id": "6234364c406b5e0bd4f9bb1b",
                        "labelName": "cats",
                        "description": "cats ",
                        "datasetId": "62343589f8afb4001e27a00c",
                        "createdAt": "2022-03-18T07:35:40.622Z",
                        "updatedAt": "2022-03-18T07:35:40.622Z",
                        "__v": 0
                    }
                }
            ],
            "img_name": "6910488063824261121.jpg",
            "img_originalname": "cats_00002.jpg",
            "img_desc": "Cyber Sercurity multi upload",
            "img_uri": "http://localhost:8080/resources/images/2022/3/18/6910488063824261121.jpg",
            "img_path": "/resources/images/2022/3/18/6910488063824261121.jpg",
            "datasetId": {
                "dataset_type": "classification",
                "_id": "62343589f8afb4001e27a00c",
                "dataset_name": "Bộ dữ liệu dev model",
                "dataset_status": "Đồng bộ",
                "description": "Bộ dữ liệu gồm chó mèo gấu"
            },
            "createdAt": "2022-03-18T07:32:25.200Z",
            "updatedAt": "2022-03-18T07:32:25.200Z",
            "__v": 0
        },
        {
            "_id": "62343589f8afb4001e27a04d",
            "labels": [
                {
                    "labelId": {
                        "_id": "6234364c406b5e0bd4f9bb1b",
                        "labelName": "cats",
                        "description": "cats ",
                        "datasetId": "62343589f8afb4001e27a00c",
                        "createdAt": "2022-03-18T07:35:40.622Z",
                        "updatedAt": "2022-03-18T07:35:40.622Z",
                        "__v": 0
                    }
                }
            ],
            "img_name": "6910488063820066817.jpg",
            "img_originalname": "cats_00003.jpg",
            "img_desc": "Cyber Sercurity multi upload",
            "img_uri": "http://localhost:8080/resources/images/2022/3/18/6910488063820066817.jpg",
            "img_path": "/resources/images/2022/3/18/6910488063820066817.jpg",
            "datasetId": {
                "dataset_type": "classification",
                "_id": "62343589f8afb4001e27a00c",
                "dataset_name": "Bộ dữ liệu dev model",
                "dataset_status": "Đồng bộ",
                "description": "Bộ dữ liệu gồm chó mèo gấu"
            },
            "createdAt": "2022-03-18T07:32:25.200Z",
            "updatedAt": "2022-03-18T07:32:25.200Z",
            "__v": 0
        }
    ],
    "total": 68,
    "message": ""
}

Now I want to add filter like this:

http://localhost:8080/backend/api/image?count=1&lskip=60&limit=5&datasetId=62343589f8afb4001e27a00c&labels.labelId=6234364c406b5e0bd4f9bb1b

I want to add filter condition like this:

&labels.labelId=6234364c406b5e0bd4f9bb1b or &labels.labelName=cats

I have converted the code of R2D2 to NodeJS for easy API calling, I want to call the API like this:

http://localhost:8080/backend/api/image?count=1&lskip=60&limit=3&datasetId=62343589f8afb4001e27a00c&labelId=62343660406b5e0bd4f9bb23

And below is the code I have migrated to NodeJS

exports.findAll = async (req, res) => {

    var objFind = {};
    var limit = parseInt(req.query.limit);
    if (isNaN(limit))
        limit = 10;
    var skip = parseInt(req.query.skip);
    if (isNaN(skip))
        skip = 0;
    var result = null; var message = "";

    var img_name = req.query.img_name;
    var img_originalname = req.query.img_originalname;
    var datasetId = req.query.datasetId;
    var labelId = req.query.labelId;
    
    
    if (img_name != undefined && img_name != null && img_name != "") {
      objFind["img_name"] = img_name;
    }

    if (img_originalname != undefined && img_originalname != null && img_originalname != "") {
        objFind["img_originalname"] = img_originalname;
      }

      if (datasetId != undefined && datasetId != null && datasetId != "") {
        objFind["datasetId"] = datasetId;
      }

      if (labelId != undefined && labelId != null && labelId != "") {
        objFind["labels"] = labelId;
      }

    objFind["is_deleted"] = false;

    await Image.aggregate([
      {
        "$match": {
          $and:[{"datasetId":ObjectId(req.query.datasetId), "is_deleted": false}]
        }
     },
     {
      "$addFields": {
      "labels": {
        "$filter": {
          "input": "$labels",
          "as": "lab",
          "cond": {
            "$eq": [
              "$$lab.labelId",
              ObjectId(labelId)
            ]
           }
          }
         }
       }
     },
    {
      $unwind: "$labels"
    },
    {
     $lookup: {
      from: "Label",
      let: {
        labelId: "$labels.labelId",
        label: "$labels"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $eq: [
                "$_id",
                "$$labelId"
              ]
            }
          }
        },
        {
          $replaceRoot: {
            newRoot: {
              $mergeObjects: [
                "$$label",
                "$$ROOT"
              ]
            }
          }
        }
       ],
        as: "labels"
      }
     },
     {
      $unwind: "$labels"
     },
     {
       $group: {
      _id: "$_id",
      createdAt: {
        $first: "$createdAt"
      },
      updatedAt: {
        $first: "$updatedAt"
      },
      datasetId: {
        $first: "$datasetId"
      },
      is_deleted: {
        $first: "$is_deleted"
      },
      img_uri: {
        $first: "$img_uri"
      },
      img_originalname: {
        $first: "$img_originalname"
      },
      img_name: {
        $first: "$img_name"
      },
      img_desc: {
        $first: "$img_desc"
      },
      img_path: {
        $first: "$img_path"
      },
      labels: {
        $push: "$labels"
       }
      }
     }, 
     { 
      "$sort": { "_id": -1 } 
     },
     {
        $skip: skip 
     },
     {
        $limit: limit
     }
     
    ]).exec(function(err, obj){
      if(err) {
         res.send({ "data" : null,"resultCode": 0,"message":"Có lỗi xảy ra : " + err });
         return;
     } else {
         if(req.query.count == "1"){
          Image.count(objFind, function(err, totalRecord){
                 res.send({"data":obj,"total":totalRecord,"message":""});
             });
           
         }else{
             res.send({"data":obj,"message":""});
         }
     }
     })
    
  
};

After calling the API: http://localhost:8080/backend/api/image?count=1&lskip=60&limit=3&datasetId=62343589f8afb4001e27a00c&labelId=62343660406b5e0bd4f9bb23 I got the following output:

{
    "data": [
        {
            "_id": "62343589f8afb4001e27a023",
            "createdAt": "2022-03-18T07:32:25.199Z",
            "updatedAt": "2022-03-18T07:32:25.199Z",
            "datasetId": "62343589f8afb4001e27a00c",
            "is_deleted": false,
            "img_uri": "http://localhost:8080/resources/images/2022/3/18/6910488063585185793.jpg",
            "img_originalname": "panda_00001.jpg",
            "img_name": "6910488063585185793.jpg",
            "img_desc": "Cyber Sercurity multi upload",
            "img_path": "/resources/images/2022/3/18/6910488063585185793.jpg",
            "labels": [
                {
                    "labelId": "62343660406b5e0bd4f9bb23",
                    "_id": "62343660406b5e0bd4f9bb23",
                    "is_deleted": false,
                    "labelName": "pandas",
                    "description": "pandas ",
                    "datasetId": "62343589f8afb4001e27a00c",
                    "createdAt": "2022-03-18T07:36:00.297Z",
                    "updatedAt": "2022-03-18T07:36:00.297Z",
                    "__v": 0
                }
            ]
        },
        {
            "_id": "62343589f8afb4001e27a022",
            "createdAt": "2022-03-18T07:32:25.199Z",
            "updatedAt": "2022-03-18T07:32:25.199Z",
            "datasetId": "62343589f8afb4001e27a00c",
            "is_deleted": false,
            "img_uri": "http://localhost:8080/resources/images/2022/3/18/6910488063576797185.jpg",
            "img_originalname": "panda_00002.jpg",
            "img_name": "6910488063576797185.jpg",
            "img_desc": "Cyber Sercurity multi upload",
            "img_path": "/resources/images/2022/3/18/6910488063576797185.jpg",
            "labels": [
                {
                    "labelId": "62343660406b5e0bd4f9bb23",
                    "_id": "62343660406b5e0bd4f9bb23",
                    "is_deleted": false,
                    "labelName": "pandas",
                    "description": "pandas ",
                    "datasetId": "62343589f8afb4001e27a00c",
                    "createdAt": "2022-03-18T07:36:00.297Z",
                    "updatedAt": "2022-03-18T07:36:00.297Z",
                    "__v": 0
                }
            ]
        },
        {
            "_id": "62343589f8afb4001e27a021",
            "createdAt": "2022-03-18T07:32:25.199Z",
            "updatedAt": "2022-03-18T07:32:25.199Z",
            "datasetId": "62343589f8afb4001e27a00c",
            "is_deleted": false,
            "img_uri": "http://localhost:8080/resources/images/2022/3/18/6910488063555825665.jpg",
            "img_originalname": "panda_00003.jpg",
            "img_name": "6910488063555825665.jpg",
            "img_desc": "Cyber Sercurity multi upload",
            "img_path": "/resources/images/2022/3/18/6910488063555825665.jpg",
            "labels": [
                {
                    "labelId": "62343660406b5e0bd4f9bb23",
                    "_id": "62343660406b5e0bd4f9bb23",
                    "is_deleted": false,
                    "labelName": "pandas",
                    "description": "pandas ",
                    "datasetId": "62343589f8afb4001e27a00c",
                    "createdAt": "2022-03-18T07:36:00.297Z",
                    "updatedAt": "2022-03-18T07:36:00.297Z",
                    "__v": 0
                }
            ]
        }
    ],
    "message": ""
}

The result was exactly what I expected, but when I remove the filter &labelId=62343660406b5e0bd4f9bb23 I get no results. According to my wish, the result should be more. I think I have some mistake in code

Please take a look. Thanks

cauchuyennhocuatoi
  • 461
  • 3
  • 8
  • 21

1 Answers1

0

Something like this:

db.images.aggregate([
 {
  "$addFields": {
  "labels": {
    "$filter": {
      "input": "$labels",
      "as": "lab",
      "cond": {
        "$eq": [
          "$$lab.labelId",
          ObjectId("6234364c406b5e0bd4f9bb1b")
        ]
       }
      }
     }
   }
 },
{
  $unwind: "$labels"
},
{
 $lookup: {
  from: "labels",
  let: {
    labelId: "$labels.labelId",
    label: "$labels"
  },
  pipeline: [
    {
      $match: {
        $expr: {
          $eq: [
            "$_id",
            "$$labelId"
          ]
        }
      }
    },
    {
      $replaceRoot: {
        newRoot: {
          $mergeObjects: [
            "$$label",
            "$$ROOT"
          ]
        }
      }
    }
   ],
    as: "labels"
  }
 },
 {
  $unwind: "$labels"
 },
 {
   $group: {
  _id: "$_id",
  createdAt: {
    $first: "$createdAt"
  },
  updatedAt: {
    $first: "$updatedAt"
  },
  datasetId: {
    $first: "$datasetId"
  },
  is_deleted: {
    $first: "$is_deleted"
  },
  img_uri: {
    $first: "$img_uri"
  },
  img_originalname: {
    $first: "$img_originalname"
  },
  img_name: {
    $first: "$img_name"
  },
  img_desc: {
    $first: "$img_desc"
  },
  img_path: {
    $first: "$img_path"
  },
  labels: {
    $push: "$labels"
   }
  }
 }
])

Explained:

  1. Filter only labels.labelId that you need in the final result.
  2. $unwind the labels array so it is easy to lookup
  3. $lookup with the labels collection
  4. $unwind one more time to join the matched.
  5. group by _id so you join the labels if there is same labelId from same array

playground

R2D2
  • 9,410
  • 2
  • 12
  • 28
  • Thank you for your reply, your answer is almost 100% what I wanted to ask, actually like I said in my question, what I want is to add a filter that is "&labelId=". This filter is optional, if I don't select this fiter, the results will still be returned, and when I select this filter, the results will be narrowed to the set with &labelId=. But now if I remove the filter "&labelId=" the result is an empty array. I have moved your code to NodeJS so you can understand what I mean, please review with me. – cauchuyennhocuatoi Mar 27 '22 at 15:59