-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mongoose Dictionary Type #5030
Comments
For tasks -> collections migrations it's needed just as an intermediary step? Like array -> dictionary -> collection? |
@paglias we should G+ about this sometime, I'm thinking much different / more complex than before. Firstly, I'm thinking a top-level collection called Each task will have top-level attrs under Very choppy version of my thought here, and I'll explain more about that structure over a G+ sometime. |
And also, if Mongoose 4.x Plugins API is different than 3.x, let's favor 4.x API and upgrade our mongoose to 4.x during the T=>C migration |
Putting my thoughts here so I won't forget them: |
@paglias that's a very good point. The challenge schema is pretty slim - users' tasks aren't stored in the challenge, instead they're looked up later as needed. However, all challenge.tasks' history is augmented with each user interaction, and if that's adding too much space then we'll definitely hit the same issue with this direction. Do you have a sample challenge UUID I can investigate? |
@lefnire from New Relic I think |
Interesting. Indeed, the history entries for each task in that challenge are some 60k entries, a very likely culprit. (We should start pruning challenge histories, or record less). The |
The best idead that came to my mind for the dictionary type is to have a
I'm quite sure it works but:
I found this feature request in Mongoose that asks for the same thing and asked the maintainer of the project if he thinks we would have any problem developing a |
Good find on the other ticket! Reading now. I wonder if we should story history entries as a collection... they're so rarely used, we could do an AJAX lookup on request? |
For challenges I think we should have the tasks schema defined inside the challenge and when a user joins the challenge we create a new tasks belonging to the user (so with its own document) and a reference to the challenge ( I think it'd the best approach for perfs, mongo... |
@lefnire I found how to implement the dictionary type, it'll use a slightly modified version of mongoose's embedded document type. But there's something we can't avoid: when adding a new item to the dictionary like:
we cannot use a simple assignement because there's no way of intercepting it, we're going to need using something like:
also if we want to set it to I think I can put up a working version quite quickly and then when we'll have the rest of the code we'll make sure it fits our needs |
Alternative is to wrap Array into Dict: |
To complete the tasks=>collection migration, we'll need a new Mongoose type
Dictionary
. Really this type would come in handy in many other situations, but it's quite required for the T=>C migration.Here's the story. In MongoDB, storing arrays turns out to be stupid. Fine for very small arrays (eg,
user.preferences.hooks
); terrible for very large or commonly-accessed arrays (eg,user.habits
). What happens is, in order to prevent race conditions on array indices, Mongoose adds an extra._v
parameter to the query on array updates. This slows down queries tremendously, creating major scalability bottlenecks at the DB layer. The solution is to store arrays as objects. Then in order to treat those objects as lists, you add asort
field for sorting, and some app logic (typically using Lodash's collections API). More and more you see vendors stop supporting arrays at the DB layer and instead use objects (eg, Firebase's post).So as an example, instead of storing
user.habits
as an array:we want to store it as an object:
Which is fine and dandy. The problem here is that
<habit-id>
. Those familiar with Mongoose know you can't do that - you can't have dictionaries, where a dynamic key maps to an object with a defined schema. What you can do is havehabits: {type: Schema.Types.Mixed, 'default': {} }
, but then you don't get Schema validation, default values,path.markModified()
, etc. and you have to validate your dictionaries manually. You can see this at play presently in a few situations: quests, filters, messages, and many more. In these situations we handle validation in app logic, and trigger.markModified()
manually.So from my searching, there's no Mongoose support for this style of Dictionary attributes, nor any existing Mongoose plugins for such (someone may wanna double check in case my Google Fu is failing me). The task at hand then is to create a new Mongoose plugin to add a new type called Dictionary. You can see how to add new types with this example. Existing types here, a likely type to copy/paste from is Array. Model defs then might look like the following:
where the key is dynamic, the schema is handled as normally the case in Mongoose (pre-save validation, type-checking, etc), and
.markModified()
is handled automatically. Further, it may be useful to add support "value dictionaries" (for lack of a better word) where the dictionary doesn't map to an object, but a single value. Eg,user.filters
is an object like{<uuid>:true, <uuid>:false}
(code). In this case, we may extend our Dictionary type so that it would work as such:Ideally this dictionary type would be open-sourced to the mongoose plugin community (see "Community!"), maybe as mongoose-dictionary-type or something.
The text was updated successfully, but these errors were encountered: