Mongoose在创建Model时对Collection的命名策略
Mongoose是MongoDB的对象模型工具,比如使用下面的代码片段就可以在MongoDB的test数据库中创建一个名字叫“user(关于这个名字是本文的重点)”的集合,集合中保存了一个文档(user1)。
var mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/test");
var db = mongoose.connection;
db.on('error', console.error.bind(console, '... connection error ...'));
db.once('open', function callback() {
console.info("... db open ...");
});
var UserSchema = mongoose.Schema({
name: String,
age: Number,
birthday: Date
});
var User = mongoose.model("user", UserSchema);
var user1 = new User({
name: "Jack",
age: 23,
birthday: new Date()
});
user1.save(function (err, user1) {
if (err) {
return console.error(err);
}
console.info(user1);
});
从创建链接到向数据库中写入一个条数据经历了以下步骤:
1.链接数据库(相当于在使用Hibernate的时候配置数据库),并创建链接;
2.定义UserSchema(相当于数据库建表) ;
3.创建User模型(相当于构建对象和数据库表映射);
4.通过User模块,创建对象
5.通过save方法持久化对象;
当然Mongoose是MongoDB的模型工具,所以这里最好不要用表,记录来描述。那么上面描述中的User模型就是MongoDB中的collection,即test数据库中的一个集合,user是指定了集合名。
运行上述程序之后,回到MongoDB的客户端查看test数据库的集合列表。
上图标注的"users"是运行程序创建的Collection,而程序中指定的模型名称为:user, 数据库中的集合名是“users”,这个问题正是本文讲述的重点(Mongoose在创建MongoDB的Collection时的命名策略)。
使用过MongoDB,应该知道向MongoDB中一个不存在的collection中插入文档,数据库会自动创建一个Collection(集合)。而在使用Monogoose的时候,发现这个问题后,又试了试如下模型名:xx, kitten,发现变化为xx―>xxes, kitten―>kittens。
开始做了个猜想,会不会Collection(集合)意味着要用复数名称,Mongoose对此做了特殊处理,当我把模型名改为:money的时候查看数据库集合发现,集合名称仍然是money。 看到这个结果,确定Mongoose在模型名至数据库集合名的命名转换上做了文章。
模型名设置为money:
当我自定义了模型名,然后在数据库集合中名称于此不对称,这不得不让人抓狂。如果正如猜想的那样,Collection的命名做了复数和不可数处理,那么是不是在命名一个模型(集合)名的时候,我还得考虑一下使用的名词单复数性。即使是考虑了,能否保证一致,那得看英语水平了。
实际开发中当然希望程序中指定的模型的命名能够一致的和数据库的集合名称对应起来,那便是极好的。出于这种想法,于是探究了一下Mongoose框架的源代码,看看 作者是如何做集合命名规范了, 发现位于mongoose/lib/util.js模块中如下代码片段是集合命名的根源。
/*!
* Produces a collection name from model `name`.
*
* @param {String} name a model name
* @return {String} a collection name
* @api private
*/
exports.toCollectionName = function (name, options) {
options = options || {};
if ('system.profile' === name) return name;
if ('system.indexes' === name) return name;
if (options.pluralization === false) return name;
return pluralize(name.toLowerCase());
};
/**
* Pluralization rules.
*
* These rules are applied while processing the argument to `toCollectionName`.
*
* @deprecated remove in 4.x gh-1350
*/
exports.pluralization = [
[/(m)an$/gi, '$1en'],
[/(pe)rson$/gi, '$1ople'],
[/(child)$/gi, '$1ren'],
[/^(ox)$/gi, '$1en'],
[/(ax|test)is$/gi, '$1es'],
[/(octop|vir)us$/gi, '$1i'],
[/(alias|status)$/gi, '$1es'],
[/(bu)s$/gi, '$1ses'],
[/(buffal|tomat|potat)o$/gi, '$1oes'],
[/([ti])um$/gi, '$1a'],
[/sis$/gi, 'ses'],
[/(?:([^f])fe|([lr])f)$/gi, '$1$2ves'],
[/(hive)$/gi, '$1s'],
[/([^aeiouy]|qu)y$/gi, '$1ies'],
[/(x|ch|ss|sh)$/gi, '$1es'],
[/(matr|vert|ind)ix|ex$/gi, '$1ices'],
[/([m|l])ouse$/gi, '$1ice'],
[/(quiz)$/gi, '$1zes'],
[/s$/gi, 's'],
[/([^a-z])$/, '$1'],
[/$/gi, 's']
];
var rules = exports.pluralization;
/**
* Uncountable words.
*
* These words are applied while processing the argument to `toCollectionName`.
* @api public
*/
exports.uncountables = [
'advice',
'energy',
'excretion',
'digestion',
'cooperation',
'health',
'justice',
'labour',
'machinery',
'equipment',
'information',
'pollution',
'sewage',
'paper',
'money',
'species',
'series',
'rain',
'rice',
'fish',
'sheep',
'moose',
'deer',
'news',
'expertise',
'status',
'media'
];
var uncountables = exports.uncountables;
/*!
* Pluralize function.
*
* @author TJ Holowaychuk (extracted from _ext.js_)
* @param {String} string to pluralize
* @api private
*/
function pluralize (str) {
// var rule, found;
// if (!~uncountables.indexOf(str.toLowerCase())){
// found = rules.filter(function(rule){
// return str.match(rule[0]);
// });
// if (found[0]) return str.replace(found[0][0], found[0][1]);
// }
return str;
};
上面代码 对集合名称做了处理,uncountables是不可数名词,rules是一组正则匹配规则。当注释掉function pluralize(str)方法中的处理代码之后,重新运行文中第一段代码,结果如下:
function pluralize(str)方法的处理思路是:
1.判断模型名是否是不可数的,如果是直接返回模型名;否则进行复数转化正则匹配;
2.返回复数转化正则匹配结果(一个复数转化正则匹配是一个数组,有两个对象,[0]正则表达式,[1]匹配后处理结果);
3.如果复数转化正则匹配结果不存在,直接返回模型名;否则取匹配结果第一个,对模型名进行处理。(需要说明的是,rules是按特殊到一般的顺序排列的)
不清楚作者出于什么考虑对模型名和集合名未做对应处理,第一次使用Mongoose的时侯产生了这个疑问,于是刨根问底看了个究竟。作此文,记录一下,如果真想保持是模型名和数据库中的集合名保持一致,不妨从源代码下手。
PS:感谢作者给我们提供了一个不错的英文名词复数化的代码段。
本文出自 “野马红尘” 博客,谢绝转载!