简体   繁体   中英

How to query an array in mongodb

Was trying to filter an array with another condition to query my MongoDB database

I have tried using the elemMatch to match exactly with the query, but it not working out.

Here is my code my shipment schema

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Create Schema
const ShipmentSchema = new Schema({
  warehouseNo:{
    type: String,
    ref: 'users.unitNo'
  },
  packages:[
    {
        category:{
            type: String
        },
        quantity:{
            type: String
        },
        description:{
            type: String
        },
        trackingno:{
            type: String,
        },
        date:{
            type: Date,
            default: Date.now
        },
        length:{
            type: Number
        },
        width:{
            type: Number
        },
        height:{
            type: Number
        },
        weight:{
            type: Number
        },
        fee:{
            type: Number, 
        },
        status: {
            type: String,
            default: "In warehouse"
        },
  },
],

  shippingMode:{
    type: String,
  },

 date:{
        type: Date,
        default: Date.now
 }
});

module.exports = Shipments = mongoose.model('shipments', ShipmentSchema);

Here is my node js.

// @route   GET api/user/package
// @desc    Get all package
// @access  Private
router.get('/package', 
  passport.authenticate('jwt', { session: false }),

 (req, res) => {
  const errors = {};

  Shipments.findOne({warehouseNo : req.user.unitNo})
    .then(shipments => {
      if (shipments.packages.length === 0) {
        errors.nopackages = 'There are no packages for you yet';
        return res.status(404).json(errors);
      }
      res.json(shipments.packages);
    })
});

The code above bring every record in my mongoddb, but if i tried the below, where i ask it to fillter by package status. i got a code crash error

// @route   GET api/user/package
// @desc    Get all package
// @access  Private
router.get('/package', 
  passport.authenticate('jwt', { session: false }),

 (req, res) => {
  const errors = {};

  Shipments.find({warehouseNo : req.user.unitNo, "packages.status": "In warehouse"})
    .then(shipments => {
      if (shipments.packages.length === 0) {
        errors.nopackages = 'There are no packages for you yet';
        return res.status(404).json(errors);
      }
      res.json(shipments.packages);
    })
});

i expect to get something like this

{
    "status": "In warehouse",
    "date": "2019-09-11T10:19:02.834Z",
    "_id": "5d78ca160e47be29e13253b5",
    "category": "liquid",
    "quantity": "10 pieces",
    "description": "garri",
    "trackingno": "MHS085533395",
    "weight": 123,
    "length": 12,
    "height": 12,
    "width": 13
  }

instead i got this

[
  {
    "status": "Shipped",
    "date": "2019-09-11T10:17:46.485Z",
    "_id": "5d78c9ca0e47be29e13253b4",
    "category": "liquid",
    "quantity": "10 pieces",
    "description": "garri",
    "trackingno": "SDG561920753",
    "weight": 123,
    "height": 12,
    "width": 13
  },
  {
    "status": "In warehouse",
    "date": "2019-09-11T10:19:02.834Z",
    "_id": "5d78ca160e47be29e13253b5",
    "category": "liquid",
    "quantity": "10 pieces",
    "description": "garri",
    "trackingno": "MHS085533395",
    "weight": 123,
    "length": 12,
    "height": 12,
    "width": 13
  }
]

You should use $elemMatch inside the key packages , ie db.getCollection('shipments').find( {warehouseNo: "123"}, { packages: { $elemMatch: { status: "In warehouse" }}}) .

For Example: I have a collection as below:

{
"_id" : 1.0,
"name" : {
    "first" : "John",
    "last" : "Backus"
},
"birth" : ISODate("1924-12-03T05:00:00.000Z"),
"death" : ISODate("2007-03-17T04:00:00.000Z"),
"contribs" : [ 
    "Fortran", 
    "ALGOL", 
    "Backus-Naur Form", 
    "FP"
],
"awards" : [ 
    {
        "award" : "W.W. McDowell Award",
        "year" : 1967.0,
        "by" : "IEEE Computer Society"
    }, 
    {
        "award" : "National Medal of Science",
        "year" : 1975.0,
        "by" : "National Science Foundation"
    }, 
    {
        "award" : "Turing Award",
        "year" : 1977.0,
        "by" : "ACM"
    }, 
    {
        "award" : "Draper Prize",
        "year" : 1993.0,
        "by" : "National Academy of Engineering"
    }
]

}

Using query like this:

db.getCollection('bios').find( {_id: 1.0 }, { awards: { $elemMatch: { year: 1967.0 }}})

Gave me a result:

{ "_id" : 1.0, "awards" : [ { "award" : "WW McDowell Award", "year" : 1967.0, "by" : "IEEE Computer Society" } ] }

Hope this will help you.

You defined warehouseNo as reference from other table. It must be some ID. Please make sure you are comparing the same

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM