1

I have a mongoose schema:

var ClientRentalSchema = new mongoose.Schema({
    carId: { 
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Car'
    },
    userId: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    },
    startDate: Date,
    endDate: Date,
    payment: Number,
    status: { type: String, default: "Oczekujące" },
    discount: { type: Number, default: 0 }
});

Now, I'm trying to find an object by the user's ID card number. Firstly the closest I got is by this piece of code:

Rental.find()
         .populate('userId', 'idNumber')
         .findOne({'userId.idNumber': 'XYZ 987654'})
        .exec( (err, values) => {
            if(err) return err;
            res.json(values);
    })

It gives a null. This is a sample rental object after popluating:

{"status":"Aktywne",
"discount":0.2,
"_id":"5ae06b49abafb90e20359892",
"carId":"5ad6186ebd371940e4131f71",
"userId":{"_id":"5ad8e077a59b7d58fc2384bd",
    "idNumber":"ABC 123456"},
"startDate":"2018-04-26T09:11:00.000Z",
"endDate":"2018-04-29T09:11:00.000Z",
"payment":237.6,
"__v":0}

What would be the proper way of searching for a rental by the users id card number?

Matt
  • 556
  • 8
  • 31
  • This appears to be a duplicate of: https://stackoverflow.com/questions/31357745/find-after-populate-mongoose, looks like the answers are run `.exec()` on the populate then filter in javascript or change the schema to contain the entire user object in the base schema. (Neither of these answers are great, but depending on your situation may work) – Phillip Thomas May 02 '18 at 16:29

3 Answers3

2

Unfortunately it seems mongoose makes this situation a bit tricky as it does not support JOINS. What I believe we need is two queries:

  1. Get the User IDs by querying the users by their "card number"
  2. Get the Rentals where the above User IDs are assigned

This might look like:

Users.findOne({'userId': 'XYZ 987654'}), (err, user) => {
    if(err) return err;

    if(user) {
      Rental
        .findOne({'userId': user._id}), (err, rental) => {
          if(err) return err;
          res.json(rental);
      });
    }
  });

And this can be easily switched to accept multiple user "card numbers" and returning multiple rentals using find() instead of findOne().

Phillip Thomas
  • 1,450
  • 11
  • 21
  • Had to make a few edits, fixed the Rental query to compare `userId` to the previously returned `user._id`. Also, shortened the syntax by removing the `exec()` and passing the function as a parameter to the `findOne()`'s. I also found this post that may provide more assistance: https://stackoverflow.com/questions/19380738/mongoose-nested-query-on-model-by-field-of-its-referenced-model – Phillip Thomas May 02 '18 at 16:46
  • but there is no need to put two queries as it can be easily done using single query – Ashh May 03 '18 at 18:18
0

Your question seems like your trying to query a single document by searching by the field userId.idNumber. If this is all your looking to do then you need to simple search by using just the findOne() with the specific field you want to match to.

Rental.findOne({'userId.idNumber': 'XYZ 987654'}, function(err, rentalDoc) {
        if(err) return err;
        res.json(values);
})
pwborodich
  • 382
  • 6
  • 22
0

Little late to the party here. One thing you could use is the Mongodb aggregation pipeline.

I think you could try something like this.

Rental.aggregate([
  {
    $lookup: {
      from: 'users',
      localField: 'userId',
      foreignField: '_id',
      as: 'rentalUsers'
    }
  },
  {$match: {'rentalUsers.idNumber': 'XYZ 987654'} }
])

Here are some comments from another post that I found that answered this question for me in the past. FYI, this was posted by sbrass. Credit goes to them for this. Here is the link: link to original post

$lookup acts like .populate(), replacing the reference with the actual data. It returns an array though since it can be used to match multiple documents.

$unwind removes items from an array, and in this case will just turn the single element array into a field.

$match then does what it sounds like and only returns documents matching the query. You can also do more complex matching than strict equality if you need.

In general the way the aggregation pipeline works is by continually filtering/modifying matching documents each step of the way until you have just what you want.

Disclaimer: I have not tested this snippet so I can't say that this query actually works. I've written a similar query recently and this is how I solved my issue. You may need to make a couple tweaks to match your needs. Hope this helps. Cheers!

Community
  • 1
  • 1
Paul
  • 163
  • 1
  • 13