Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose: Find label in array and return matching documents

In my current Mongo DB, I have a simple Parts collection, with a Parent Children relationship, like the following:

{"partcode": "Parent1","children": ["Child1","Child2","Child3"]}

{"partcode": "Child1","label": ["label1"]}
{"partcode": "Child2","label": ["label1"]}
{"partcode": "Child3","label": ["label1"]}

In order to return the children of a partcode, I use the following Mongoose function:

PartSchema.static('getChildren', function(query, callback) {
  var self = this,
  self.findOne(query, {children: 1, _id: 0})
    .exec(function(err, doc) {
      return (self.find({
        "partcode": {
          "$in": doc.children
        }
      }, {_id: 0}, callback));
    });
});

This returns the following array:

[{"partcode": "Child1","label": ["label1"]},
{"partcode": "Child2","label": ["label1"]},
{"partcode": "Child3","label": ["label1"]}]

I'd like to implement a label system, whereby I can specify a label as a meta-child, and for the code to return all children matching that label.

{"partcode": "Parent1","children": ["*label1"]}

would return:

[{"partcode": "Child1","label": ["label1"]},
{"partcode": "Child2","label": ["label1"]},
{"partcode": "Child3","label": ["label1"]}]

I'll specify a label in the parent document's children field as starting with a special character (currently, I'm using '*', but happy to change that to something else if needs be).

Pseudocode:

  1. find Parent
  2. Get Parent's children array
  3. In array, if child starts with label character
    1. get array of all partcodes of parts that match label and
    2. substitute partcodes for label in children array
  4. return children array

Children that aren't prefaced with a label character should also be returned.

like image 992
Terry Avatar asked Aug 06 '16 09:08

Terry


1 Answers

I got this to work as follows:

PartSchema.static('getChildren', function(query, callback) {
  var self = this,
    children = [],
    labels = [];
  self.findOne(query, {children: 1, _id: 0})
    .exec(function(err, doc) {
      //find labels
      labels = _.filter(doc.children, obj => /^\*/.test(obj));
      //remove labels from children array
      children = _.difference(doc.children, labels);
      //remove label identifier '*'
      labels = _.map(labels, label => label.substring(1));
      self.find({
        vendor: vendor,
        $or: [{
          "partcode": {
            "$in": children
          }
        }, {
          "label": {
            "$in": labels
          }
        }]
      }, {_id: 0}, callback);
    });
});

I'd be interested in comments. Particularly around elegance, structure, convention, etc. Anything so poor form or ugly, it makes your eye tick?

like image 108
Terry Avatar answered Oct 03 '22 17:10

Terry