0

I am trying to write a mapReduce query to find the car with the lowest value of price plus mileage for each manufacturer. I am fairly new to this and am not sure how to emit a pair of values(i.e Milage & Price) then reduce them to a single value.

var mapFunction = function () {
  var key = this._id;
  var values = [this.Milage, this.Price];
  emit(key, values);
};

//Reducing failes here!
var reduceFunction = function (key, values) {
  let reducedValue = 0;
  values.forEach((num) => {
    reducedValue += parseFloat(num);
  });
  return reducedValue;
};

lowestValuePerManufacturer = async () => {
  const client = await MongoClient.connect(url, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  }).catch((err) => console.log("Could not connect to MongoDB", err));

  try {
    const db = client.db(dbName);
    const collection = db.collection(collectionName);
    //Query starts here!
    const res = await collection.mapReduce(mapFunction, reduceFunction, {
      out: { inline: 1 },
    });
    console.log(res);
  } catch (err) {
   ///
  }
};

Data is an array of car objects as

{
    "Manufacturer": "Fiat",
    "Colour": "Black",
    "Model": "Panda",
    "Milage": 33292.0,
    "Price": 2668.32,
    "Classification": "Motor Cars",
    "Extras": [
        "SatNav",
        "ABS"
    ]
},
2
  • Hi. Why do you need map/reduce? when you can group the data by manufacturer and find the lowest price. As you can see in official documentation, MongoDB encourages you to use aggregation pipeline with $group instead of map/reduce: docs.mongodb.com/manual/core/map-reduce Commented Apr 7, 2021 at 12:45
  • Hello @DheemanthBhat I did go through the same docs I was going to try and use $group after this. Can you give me insights on how to use aggregation pipeline to achieve what I'm trying? Commented Apr 7, 2021 at 13:25

1 Answer 1

1

So the idea is using aggregation:

  1. First group the documents by Manufacturer using $group operator.
  2. Then find minimum value for the sum of Price and Milage using $min operator.

Try this query:

db.cars.aggregate([
    {
        $group: {
            _id: "$Manufacturer",
            min_price_mileage: {
                $min: {
                    $add: ["$Price", "$Milage"]
                }
            }
        }
    },
    {
        $project: {
            _id: 0,
            Manufacturer: "$_id",
            min_price_mileage: "$min_price_mileage"
        }
    }
]);

Output:

/* 1 */
{
    "Manufacturer" : "Audi",
    "min_price_mileage" : 36020
},

/* 2 */
{
    "Manufacturer" : "Hyundai",
    "min_price_mileage" : 22083
}

Test data in cars collection:

[
    {
        "_id": ObjectId("..."),
        "Manufacturer": "Hyundai",
        "Colour": "Black",
        "Model": "Accent",
        "Milage": 29,
        "P15395ice": 1
    },
    {
        "_id": ObjectId("..."),
        "Manufacturer": "Hyundai",
        "Colour": "Red",
        "Model": "Venue",
        "Milage": 33,
        "Price": 22050
    },
    {
        "_id": ObjectId("..."),
        "Manufacturer": "Audi",
        "Colour": "Blue",
        "Model": "Q3",
        "Milage": 20,
        "Price": 36000
    },
    {
        "_id": ObjectId("..."),
        "Manufacturer": "Audi",
        "Colour": "Blue",
        "Model": "A4",
        "Milage": 31,
        "Price": 40900
    }
]
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you! I'll still try to make an equivalent of this using map/reduce since it falls for my assignment. sheesh
yeah i figured something like this! Thank you again

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.