简体   繁体   中英

How to reformat data only for saving to MongoDB with Mongoose to avoid “not okForStorage”?

I have Schema defined in Mongoose and I just realized one attribute is being saved as object (kind of hash), but it can contain prohibited characters in it's keys. By prohibited I mean those which are not very much liked by MongoDB, causing not okForStorage errors: dots, dollar signs, etc.

As I don't want to change all my application, I want to define something on my model which reformats the object to array before passing it to MongoDB and, of course, I need also something reformatting it back when loading such data from MongoDB.

I tried getters and setters and played a while with Middleware , but could not make it working. Is there a best practise on this? What would be the best approach? I really wish I could just stick two functions somewhere on the schema and it would be pure blackbox for the rest of my app.

UPDATE: What I want to achieve (example):

toMongo = function (mapping) {
    // from {'k': 'v', ...} makes [{key: 'k', value: 'v'}, ...]
    return ...
}

fromMongo = function (mapping) {
    // from [{key: 'k', value: 'v'}, ...] makes {'k': 'v', ...}
    return ...
}

schema = mongoose.Schema({
    mapping: mongoose.Schema.Types.Mixed
});

var Foo = mongoose.model('Foo', schema);
var foo = new Foo({ mapping: {'tricky.key': 'yes', 'another$key': 'no'} });

foo.mapping // results in {'tricky.key': 'yes', 'another$key': 'no'}

foo.save(function(err, doc) {
   // mapping is actually saved as
   // [{key: 'tricky.key', value: 'yes'}, {key: 'another$key', value: 'no'}] in mongo!

   doc.mapping // results in {'tricky.key': 'yes', 'another$key': 'no'}
});

Foo.find(function (err, foos) {
    foos[0].mapping // results in {'tricky.key': 'yes', 'another$key': 'no'}
});

The question is: Where should I hook my two magic functions toMongo and fromMongo so the interface works exactly as I shown in the example?

(Disclaimer: At the time of this question is asked, I am Mongoose & Node.js noob, so even silly details could be helpful to me)

I think I found the answer myself. It can be solved with Middlewares , this way:

schema.post('init', function (doc) {
    doc.mapping = fromMongo(doc.mapping);
}

schema.pre('save', function (next) {
    this.mapping = toMongo(this.mapping);
    next();
}

This way it's pretty isolated from the rest of the app and so far I didn't have any problems with this solution. I'll try to keep updating this answer in case any problems rise up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM