简体   繁体   中英

MongoDB: Query elements of an array of objects nested in a collection property

I have a Mongo DB database set up with the following collection, Races:

[
    {
        "_id": "5a24b47f8b8498252a0a0ef9",
        "year": 2017,
        "runners": [
            {
                "Place": "1",
                "Div/Tot": "1/126",
                "FName": "XXXX",
                "LName": "XXXX",
                "Num": "XXXX",
                "S": "M",
                "Ag": "25",
                "City": "XXXX",
                "St": "XX",
                "Gun-Time": "32:15.2",
                "Net-Time": "32:14.91",
                "Pace": "5:13"
            },
            {
                "Place": "2",
                "Div/Tot": "1/138",
                "FName": "XXXX",
                "LName": "XXXX",
                "Num": "XXXX",
                "S": "M",
                "Ag": "34",
                "City": "XXXX",
                "St": "XXXX",
                "Gun-Time": "MD",
                "Net-Time": "32:19.0",
                "Pace": "32:18.78"
            },
        ....

I am trying to query by year to bring up the right element of the collection, and then query within the element's "runners" array based on input criteria. So far I have not been able to direct the query into this array. The goal is to derive members of an array of objects held within an element of a collection.

I looked at the syntax for mongo DB's $in and $all operators but I have not been able to construct a query that matches against the properties of the objects in the array.

I am using Node and this is the end-point I have tried to adapt;

router.route( '/race/:year' )
  .get( ( req, res ) => {
      console.log( 'query', req.query, ' params ', req.params ); 
      Race.find( { year: req.params.year }, {runners: {$elemMatch: req.query } } )  
      .then( race => {
          return res.json( race );
      } )
      .catch( () => res.status( 500 ).send( 'endpoint error..........' ) );
});

The problem with this query is that it only returns the first array element that matches req.query , not all of the values that do.

Is there a concise way to construct a query into the objects of the array that returns all of the matches? Thank you for your time.

This should get you started:

Race.aggregate([
{ 
    $match: {
        "year": req.params.year // filter out all documents that we're not interested in
    }
}, {
    $project: {
        _id: 0
        "runners": {
            $filter: {
                input: "$runners", // we want to filter the "runners" array
                as: "runner",
                cond: {
                    $eq: [ "$$runner.Ag", "34" ] // just an example filter
                }
            }
        }
    }
}], function(err, results) {
      rs.json(results);
});

Thank you Alex for the suggestion to try aggregation or the filters. I could not get the filter to work, based on what I read from the docs but I was able to get it working with this:

router.route( '/race/:year' )
  .get( ( req, res ) => {
      console.log( 'query', req.query, ' params ', req.params ); 

      Race.find( { year: req.params.year } )
     .then( race => {
        let results = [];
        const runners = race[ 0 ].runners;
        const searchObj = req.query;
        const searchKeys = Object.keys( searchObj );

        for ( let i = 0; i < runners.length; i++ ){
            searchKeys.forEach( function( searchTerm ){ 
                if ( runners[ i ][ `${ searchTerm }` ] === searchObj[ `${ searchTerm }` ] ){
                    results.push( runners[ i ] );
                }
            }
        ) } 
        return res.json( results );
      })
      .catch( () => res.status( 500 ).send( 'endpoint error..........' ) );
});

This works for a single search term, but if the requirement were runners who had more than one characteristic this would return runners with any of the characteristics, not the set of runners that has all of them. It seems that MongoDB should have something to make this less painful...

If anyone has any suggestions I would appreciate the help in refactoring. Thank you.

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