loopbackio / loopback-connector-mongodb

The official MongoDB connector for the LoopBack framework.
https://loopback.io/doc/en/lb4/MongoDB-connector
Other
187 stars 236 forks source link

embedsMany creates plain-text IDs, but tries to query as BSON #338

Closed frankorama closed 7 years ago

frankorama commented 7 years ago

Bug or feature request

Description of feature (or steps to reproduce if bug)

We have a model "TagGroup" which embeds a model "Tag" with an embeds many relationship:

// Tag group model
{
  "name": "TagGroup",
  "base": "PersistedModel",
  "relations": {
    "attributes": {
      "type": "embedsMany",
      "model": "Tag",
      "property": "_tag",
      "options": {
        "validate": true,
        "forceId": false
      }
    }
}

// Tag model
{
  "name": "Tag",
  "base": "Model",
  "options": {
    "validateUpsert": true
  },
  "properties": {
    "name": {
      "type": "string",
      "required": true
    }
  }
}

.. such that a tag group (Book Type), can have many tags (Fiction, Biography, Non-Fiction, etc.)

When a new Tag Group is created, the ID is a BSON in MongoDB. When a new Tag is created, the ID is a string

Associating tags to books We associate Tags to Books using an array of strings because we were unable to figure out how to create a relation between a Model and an embedded model such that the books model looks like this:

// Book model
{
  "name": "Book",
  "base": "PersistedModel",
  "options": {
    "validateUpsert": true
  },
  "properties": {
    "tags": {
      "type": ["string"],
      "required": false
    }
  }
}

When we associate tags to books, the data looks like this in Mongo:

{
  "name": "Some book title",
  "tags": ["5812417b6a35cc168585a4b5","5812417b6a35cc168585a4ba"]
}

Link to sample repo to reproduce issue (if bug)

(I can create one upon request)

Expected result

When I try to query a book by a tag in the explorer:

{"where":{"tags":"5812417b6a35cc168585a4b5"}}

The loopback-connector-mongodb should convert the query to this:

{"tags":"5812417b6a35cc168585a4b5"}

... and locate the associated books

Actual result (if bug)

The loopback-connector-mongodb converts the query to this:

{"tags":ObjectId("5812417b6a35cc168585a4b5")}

... and does not locate the associated books because the loopback-connector-mongodb detects if a value is an object id property by using a regular expression:

/**
 * Check whether the property is an ObjectID (or Array thereof)
 *
 */
MongoDB.prototype.isObjectIDProperty = function(model, prop, value) {
  if (prop && ((prop.type === ObjectID) || (Array.isArray(prop.type) && prop.type[0] === ObjectID))) {
    return true;
  } else if ('string' === typeof value) {
    var settings = this._models[model] && this._models[model].settings;
    var strict = (settings && settings.strictObjectIDCoercion) || this.settings.strictObjectIDCoercion;
    if (strict) return false; // unless explicitly typed, don't coerce
    return /^[0-9a-fA-F]{24}$/.test(value);
  } else {
    return false;
  }
};

Additional information (Node.js version, LoopBack version, etc)

"loopback": "^2.37.1" "loopback-connector-mongodb": "^1.18.0" "loopback-datasource-juggler": "^2.54.0" MongoDB: 3.2

Questions about best-practice

Can/should embedsMany models be used as foreign keys? In my example should my TAGS model be a separate persisted model?

We did several tests trying to "relate" books and tags together, but were not successful. It would appear that embedsMany is useful for creating child objects that you want to copy to another document and never change once copied. Example: address on a shipping form. A user's address might change, but the address "copied" to the shipping form should never change once assigned, therefore no relationship.

stale[bot] commented 7 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 7 years ago

This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.