Chris Vilches
Chris Vilches

Reputation: 1187

How can I do a Many-to-Many where clause in Sails.js/Waterline?

I have this code

Image.find({ tags: {id: 3}}).exec(console.log);

which is wrong, but my intention is to find all images that have the tag id 3.

An image can have many tags, and many images can be tagged with the same tag (many-to-many).

Model code.

Image

module.exports = {
    attributes: {
        tags: {
            collection: 'Tag',
            via: 'images'
        }
    }
};

Tag

module.exports = {
    attributes: {
        images: {
            collection: 'Image',
            via: 'tags'
        }
    }
};

I don't want to use SQL raw queries, nor I want to use N+1 queries to populate everything.

I also tried using .populate() by using Image.find(3).populate("images")... but it will only populate the images, but each image won't have tags, so this doesn't work for me.

Upvotes: 1

Views: 306

Answers (1)

Sangharsh
Sangharsh

Reputation: 3019

You can use below code.

Below code may still do N+1 queries internally.
Best way to check will be to enable query logs in database.

Note: I haven't checked code for syntax errors.

function findImagesByTagId(tagId, callback) {
  Tag.findOne(tagId)
    .populate("images")
    .exec(function(err, tag) {
      if (err) {
        return callback(err);
      }
      if (!tag) {
        return callback(new Error('tag not found: ' + tagId));
      }
      // Collect all image ids
      var imageIds = _.map(tag.images, 'id');

      Image.find(imageIds)
        .populate('tags')
        .exec(callback);
    });
}

Upvotes: 1

Related Questions