jedireza / mongo-models

:package: Map JavaScript classes to MongoDB collections
MIT License
67 stars 28 forks source link

Mongo Lookup Support #23

Closed gregfrasco closed 7 years ago

gregfrasco commented 7 years ago

MongoDB lookup commands do not support lookup with object id and a string id. Reference ticket. Most of my other collections have a userId field that is a string ID, and maybe others do too. I created a function to do something similar.

I can create tests and then a pull request, if interested. Also intrested in adding a pagedFind Lookup as well because that would help me more in my porjects. Lookup By Id Function

Usage

User Collection:

[
  {
    "_id": "ObjectId(59d519e18b3aca4544fed939)",
    "username": "testUser1",
    "email": "test1@email.com"
  },
  {
    "_id": "ObjectId(57e50b2e14096f000334a4b7)",
    "username": "testUser2",
    "email": "test2@email.com"
  }
]

Example Collection (Mood):

Schema:

{
  "_id": "ObjectId",
  "mood": "string",
  "userId": "string",
  "timeCreated": "date"
}

Collection:

[
  {
    "_id": "ObjectId(57e2a2dc71c112000321d767)",
    "mood": "happy",
    "userId": "59d519e18b3aca4544fed939",
    "timeCreated": "2017-10-04 13:26:57.669"
  },
  {
    "_id": "ObjectId(57e0c26a5b903e0003a131ec)",
    "mood": "sad",
    "userId": "59d519e18b3aca4544fed939",
    "timeCreated": "2017-10-05 13:26:57.669"
  },
  {
    "_id": "ObjectId(57e0b0e95b903e0003a131e0)",
    "mood": "sad",
    "userId": "57e50b2e14096f000334a4b7",
    "timeCreated": "2017-10-06 13:26:57.669"
  },
  {
    "_id": "ObjectId(57e071ab61317900039159be)",
    "mood": "sad",
    "userId": "57e50b2e14096f000334a4b7",
    "timeCreated": "2017-10-07 13:26:57.669"
  }
]

Function

Mood.joinById(filter, ForeignCollection, joinField, localField,callback);

Example

const Mood = require('./models/mood');
const User = require('./models/user');

Mood.joinById({}, User, 'userId', 'user', callback);

returns

[
  {
    "_id": "ObjectId(57e2a2dc71c112000321d767)",
    "mood": "happy",
    "userId": "59d519e18b3aca4544fed939",
    "timeCreated": "2017-10-04 13:26:57.669",
    "user": [
      {
        "_id": "ObjectId(59d519e18b3aca4544fed939)",
        "username": "testUser1",
        "email": "test1@email.com"
      }
    ]
  },
  {
    "_id": "ObjectId(57e0c26a5b903e0003a131ec)",
    "mood": "sad",
    "userId": "59d519e18b3aca4544fed939",
    "timeCreated": "2017-10-05 13:26:57.669",
    "user": [
      {
        "_id": "ObjectId(59d519e18b3aca4544fed939)",
        "username": "testUser1",
        "email": "test1@email.com"
      }
    ]
  },
  {
    "_id": "ObjectId(57e0b0e95b903e0003a131e0)",
    "mood": "sad",
    "userId": "57e50b2e14096f000334a4b7",
    "timeCreated": "2017-10-06 13:26:57.669",
    "user": [
      {
        "_id": "ObjectId(57e50b2e14096f000334a4b7)",
        "username": "testUser2",
        "email": "test2@email.com"
      }
    ]
  },
  {
    "_id": "ObjectId(57e071ab61317900039159be)",
    "mood": "sad",
    "userId": "57e50b2e14096f000334a4b7",
    "timeCreated": "2017-10-07 13:26:57.669",
    "user": [
      {
        "_id": "ObjectId(57e50b2e14096f000334a4b7)",
        "username": "testUser2",
        "email": "test2@email.com"
      }
    ]
  }
]

you can also add filters and options like this:

const Mood = require('./models/mood');
const User = require('./models/user');

const moodFields = User.fieldsAdapter('mood') //joinField is added in be default as well
const moodOptions = null //must have null for correct arguments
const userFields = User.fieldsAdapter('username')
//not need for userOptions if null

Mood.joinById({}, User, 'userId', 'user', moodFields, moodOptions, userFields,callback);

returns

[
  {
    "_id": "ObjectId(57e2a2dc71c112000321d767)",
    "mood": "happy",
    "userId": "59d519e18b3aca4544fed939",
    "user": [
      {
        "_id": "ObjectId(59d519e18b3aca4544fed939)",
        "username": "testUser1"
      }
    ]
  },
  {
    "_id": "ObjectId(57e0c26a5b903e0003a131ec)",
    "mood": "sad",
    "userId": "59d519e18b3aca4544fed939",
    "user": [
      {
        "_id": "ObjectId(59d519e18b3aca4544fed939)",
        "username": "testUser1"
      }
    ]
  },
  {
    "_id": "ObjectId(57e0b0e95b903e0003a131e0)",
    "mood": "sad",
    "userId": "57e50b2e14096f000334a4b7",
    "user": [
      {
        "_id": "ObjectId(57e50b2e14096f000334a4b7)",
        "username": "testUser2"
      }
    ]
  },
  {
    "_id": "ObjectId(57e071ab61317900039159be)",
    "mood": "sad",
    "userId": "57e50b2e14096f000334a4b7",
    "user": [
      {
        "_id": "ObjectId(57e50b2e14096f000334a4b7)",
        "username": "testUser2"
      }
    ]
  }
]
jedireza commented 7 years ago

Thanks for creating an issue and sharing your ideas about this. I don't think this fits well with the current design of mongo-models.

Also $lookup is used via the aggregate method on a collection. We do expose an aggregate method. See the docs here: https://github.com/jedireza/mongo-models/blob/master/API.md#aggregatepipeline-options-callback

So $lookup would just be part of the pipeline argument we pass to aggregate. I think the proper solution would be to wait for a type conversion mechanism as discussed here: https://jira.mongodb.org/browse/SERVER-24947.

I'll close this issue for now, but please feel free to continue the conversation and/or create new issues in the future. Thanks again for being active with the project.


Minor note: Your function is named lockupById when I think you meant lookupById.