1

I'm having some hard times trying to discovery the right way to query something in the mongoose when I have a relationship.

Basically I have one document with ObjectId relating another document (as you can see bellow).

But When I try to filter a property of the reference, nothing works anymore. Basically, the problem is this line ".where({ "Recipe.Title": new RegExp("*") })"

// const configs
const config = require('./config');

// mongodb setup
const mongoose = require('mongoose');
mongoose.connect(config.database);
var Schema = mongoose.Schema

// recipe schema
const RecipeSchema = mongoose.Schema({
  Title: { type: String },
  Description: { type: String },
  Complaints: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Complaint' }],
}); 
const Recipe = mongoose.model('Recipe', RecipeSchema);

// complaint schema
const ComplaintSchema = mongoose.Schema({
  Recipe  : { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
  Message: { type: String }
});
const Complaint = mongoose.model('Complaint', ComplaintSchema);

/*
    after inserting some items
*/

Complaint
    .find()
    .populate("Recipe")
    .where({ "Recipe.Title": new RegExp("*") }) // this is not working!
    .exec((error, items) => {
        items.map((item) => {
            console.log(item);
        });
    });

Does someone have the correct way to solve it?

Eduardo Spaki
  • 1,128
  • 1
  • 8
  • 18

1 Answers1

5

(1) new RegExp("*") does not seem to be a valid regular expression because * is special and means to repeat 0 or more times whatever is before it in e.g. a* means 0 or more a's.

If you are trying to use *, you need to escape it: new RegExp('\\*')

(2) I think you're better off using match (see Query conditions and other options).

Complaint.find().populate({
    path: "Recipe"
    match: {
        title: new RegExp('\\*')
    }
}).exec(...);

Though I believe this will get ALL complaints and populate those with recipes that match regular expression.

If you really want only complaints with recipes matching regular expression, you're probably better off doing it the other way around.

Recipe.find({ title: new RegExp('\\*') }).populate('Complaints').exec(...)

Or using aggregation where you would use $lookup to join Recipes collection and $match to filter documents.

Edit: I believe it would be something like

Complaint.aggregate([
    // join Recipes collection
    {
        $lookup: {
            from: 'Recipes',
            localField: 'Recipe',
            foreignField: '_id',
            as: 'Recipe'
        }
    },
    // convert array of Recipe to object
    {
        $unwind: '$Recipe'
    },
    // filter
    {
        $match: {
            'Recipe.title': new RegExp('\\*')
        }
    }
]).exec(...)
Mikey
  • 6,728
  • 4
  • 22
  • 45
  • using the **match**, I'll just get the complaint but with the **null** recipe. But actually I want the complaints where the recipe title match my regex – Eduardo Spaki Jul 26 '17 at 11:42
  • @EduardoSpaki Right, which is why I added the last commentaries about doing it the other way around OR doing aggregation. – Mikey Jul 26 '17 at 13:10
  • 1
    yeap... I tested and it worked... I was just confusing in the beginning... because actually the **from** is **recipes** (lowercase), and **.Title** has the upper **T** – Eduardo Spaki Jul 29 '17 at 16:03