Coder1000
Coder1000

Reputation: 4461

How to query all articles from a specific user?

CODE:

server-side

     /**
     * List of Articles
     */
    exports.list = function (req, res) {
      Article.find({ 'user.displayName': 'GIGANTOR !' }).sort('-created').populate('user', 'displayName').exec(function (err, articles) {
        if (err) {
          return res.status(422).send({
            message: errorHandler.getErrorMessage(err)
          });
        } else {
          res.json(articles);
        }
      });
    };

SITUATION:

What I tried above does not work. I checked the mongoose docs: http://mongoosejs.com/docs/queries.html

but can't seem to get the query to work. Currently, the query just returns nothing.


QUESTION:

How to query all articles by a user with a specific displayName ?

Upvotes: 0

Views: 53

Answers (2)

Coder1000
Coder1000

Reputation: 4461

Just putting the code I ended up using here for people who could need it:

/**
 * List of Articles
 */
exports.list = function (req, res) {
  Article.find({ user: req.user._id.toString() }).sort('-created').populate('user', 'displayName').exec(function (err, articles) {
    if (err) {
      return res.status(422).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(articles);
    }
  });
};

Upvotes: 0

Josh Beam
Josh Beam

Reputation: 19772

TL;DR You can't query a document by a field that belongs to a populated object.

Since article simply has a ref to User, you'll have just get all articles, and then filter them in memory. Or, since the article.user field is an _id, you can find articles by the user ID (but your question is asking about finding them by user.displayName).

Mongoose populate does not do the populating in the MongoDB server itself; it populates on the application server. This means that multiple round-trips to the database are happening (see article Understanding Mongoose Population.) Therefore, you can't query by a field that exists as part of a populated object.

So, here's your 2 solutions:

  Article.find({}).sort('-created').populate('user', 'displayName').exec(function (err, articles) {
    if (err) {
      return res.status(422).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      let filteredArticles = articles
      .filter(article => article.user.displayName === 'GIGANTOR !');

      res.json(filteredArticles);
    }
  });

Or, if you can query by _id, you can do this:

  Article.find({ user: 'somemongoobjectidofuser' }).sort('-created').populate('user', 'displayName').exec(function (err, articles) {
    if (err) {
      return res.status(422).send({
        message: errorHandler.getErrorMessage(err)
      });
    } else {
      res.json(articles);
    }
  });

It gets to be a bit hairy and out of scope of the question, but another solution is the aggregation pipeline, which is only usually recommended for backend analytics. But, it'll provide you more flexibility in your query (especially if you user MongoDB's new $graphLookup).

Or, you can always store a copy of the user as a denormalized object inside the article document itself, but then you run into the much-discussed issue of maintaining denormalized documents in-sync.

Upvotes: 1

Related Questions