leodinas-hao / mongoose-query-parser

Convert url query string to MongooseJs friendly query object including advanced filtering, sorting, population, string template, type casting and many more...
MIT License
68 stars 17 forks source link

Deep population support #3

Closed ivan-rangel closed 2 years ago

ivan-rangel commented 6 years ago

Hi there great tool you've created.

I'm having issues with deep population.

It seems the current version only support first-level population and ignore the rest of the fields.

Query Params:

?populate=_lastRequests._sender.username

Current Results:

"_lastRequests": [
                {
                    "_id": "5ba11cf4bc60615625594146",
                    "_sender": "5b8ee934aaad4e4de8fffc96"
                }
   ],

Expected Result:

"_lastRequests": [
                {
                    "_id": "5ba11cf4bc60615625594146",
                    "_sender": {
                         "_id":"5b8ee934aaad4e4de8fffc96",
                         "username":"ANY"
                }
   ],

Hope yo have a chance to take a look at this. Thanks!!

leodinas-hao commented 5 years ago

Hi @ivan-rangel thanks for opening the issue & sorry for the late response. If this feature is still a must-have for you. You're more than welcome to submit a PR for it.

leodinas-hao commented 5 years ago

Issue closed

robcaa commented 3 years ago

@leodinas-hao I rewrote the castPopulate method to allow deep population and multiple select fields. Here is the code:

const castPopulate = function(val) {
  return val.split(",").map(function(qry) {
    var array = qry.split(".");
    const insertPopulate = (index = 0) => {
      if (array[index + 1]) {
        return {
          path: array[index],
          populate: insertPopulate(index + 1),
        };
      } else {
        const i = array[index].indexOf(":");
        if (i > -1) {
          const elements = array[index].split(":");
          return { path: elements.shift(), select: elements.join(" ") };
        } else {
          return { path: array[index] };
        }
      }
    };

    return insertPopulate();
  });
};

There is a little syntax change: The population separator is still the '.' character, but if you want to set select fields you need to separate them with the ':' character.

Here are some test case and the results:

console.log(JSON.stringify(castPopulate("level1"), null, 4));
console.log(JSON.stringify(castPopulate("level1:field1:field2"), null, 4));
console.log(JSON.stringify(castPopulate("level1,level1.level2.level3:field1:field2"), null, 4));
[
    {
        "path": "level1"
    }
]
[
    {
        "path": "level1",
        "select": "field1 field2"
    }
]
[
    {
        "path": "level1"
    },
    {
        "path": "level1",
        "populate": {
            "path": "level2",
            "populate": {
                "path": "level3",
                "select": "field1 field2"
            }
        }
    }
]

Can you update the package, if you think the code is correct?

leodinas-hao commented 3 years ago

Thanks a lot @robcaa, I'll have a look.

TobiasDuelli commented 2 years ago

Any updates on this @leodinas-hao ?

leodinas-hao commented 2 years ago

First of all, thanks again to @robcaa for providing a way of building deep populate support. However as the proposed approach will impact the existing usage of "populate" given new approach is taking : as the separator for field selection. I'll be looking into if there is a way to support deep populate but not affecting the existing use.

leodinas-hao commented 2 years ago

Any updates on this @leodinas-hao ?

@TobiasDuelli , you're welcome to submit a PR if you have a solution, which doesn't break the existing use.

leodinas-hao commented 2 years ago

Deep populate is supported with new release v1.3.0. Issue closed.