0

When a user saves a question, the question can contain an array of "tags". I want to take that array of tags and check to see if they exist in the tag collection. If the tags exist, update the count, if not, add it to the collection. I have code written to do this but it seems very verbose. Is there a better/easier/more concise way to do this with mongo/mongoose? The functionality is kind of similar to how stack overflow works with it's tagging.

apiRouter.post('/', function(req, res) {
    var question = new Questions();

    question.text = req.body.text;
    question.answers = req.body.answers;
    question.tech = req.body.tech;
    question.tags = req.body.tags;
    question.level = req.body.level;
    question.createdAt = req.body.createdAt;

    question.save(function(err, questions) {
        if(err) res.send(err);
        res.json({message: "Question was created."});
    });

    for each(tag in req.body.tags) {
        QuestionTags.find({ 'tag': { $regex: new RegExp(tag, "i") } }, function(err, tags) {
            if(err) res.send(err);
            if(tags.length === 0) {
                var tagObj = new QuestionTags();
                tagObj = {
                    tag: tag,
                    count: 0
                }
                tagObj.save(function(err, questions) {
                    if(err) res.send(err);
                    res.json({message: "Tag created"});
                });
            } else {
                var tagObj = new QuestionTags();
                tagObj = tags;

                tagObj.count++;

                tagObj.save(function(err, questions) {
                    if(err) res.send(err);
                    res.json({message: "Tag updated"});
                })
            }
        })
    }
});

1 Answer 1

1

You can use the MongoDB $in operator expression when using find() with stream() from the Mongoose API. find() returns a Query object which can then be used to create a QueryStream (which implements the Node.js ReadableStream interface). You can then use .on to handle each stream event.

Note that you cannot use $regex operator expression inside of an $in expression, so you will have to take care of that before passing the array into find().

apiRouter.post('/', function(req, res) {
    var question = new Questions();

    question.text = req.body.text;
    question.answers = req.body.answers;
    question.tech = req.body.tech;
    question.tags = req.body.tags;
    question.level = req.body.level;
    question.createdAt = req.body.createdAt;

    question.save(function(err, questions) {
        if(err) res.send(err);
        res.json({message: "Question was created."});
    });

    var tagsRegExp = [];

    req.body.tags.forEach(function(tag) {
        tagsRegExp.push(new RegExp(tag, "i");
    }

    QuestionTags.find({ 'tag': { $in : tagsRegExp }}).stream()
        .on('error', function(err) {
            res.send(err);
        }).on('data', function(tag) {
            if(tag.length === 0) {
                var tagObj = new QuestionTags();
                tagObj = {
                    tag: tag,
                    count: 0
                }
                tagObj.save(function(err, questions) {
                    if(err) res.send(err);
                    res.json({message: "Tag created"});
                });
            } else {
                var tagObj = new QuestionTags();
                tagObj = tag;

                tagObj.count++;

                tagObj.save(function(err, questions) {
                    if(err) res.send(err);
                    res.json({message: "Tag updated"});
                });
            }
        });
    });
Sign up to request clarification or add additional context in comments.

5 Comments

This doesn't quite work...Everything inside QuestionTags.find no longer applies because it's not inside the forEach anymore. If tagsRegExp contains 6 tags and 5 of them exist in the collection, then you will get back those 5 tags in the query response. That doesn't help create a new tag for something that doesn't exist.
@erichardson30 I've updated the code and explanation using Mongoose QueryStream on the Query object returned from find().
that's not saving anything to the questionTags collection
Can you post some example data?
the tag data is super simple and straight forward. It's just an array of strings ["Java", "javascript", "agile"]

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.