Mongoose / MongoDB 索引异常
Mongoose / MongoDB Index Exception
完整项目位置:
http://github.com/FredLackey/...
有没有人看到下面的异常?知道如何度过难关吗?我的模型确实有索引,所以我能想到没有理由不存在索引。
MongoDB 客户端代码在 Mongoose 中抛出异常...
C:\_\GuestbookLite\Projects\GuestbookLiteCatalog>npm start
> GuestbookLiteCatalog@0.1.0 start C:\_\GuestbookLite\Projects\GuestbookLiteCatalog
> nodemon ./scripts/www.js
3 Apr 17:20:45 - [nodemon] v1.3.7
3 Apr 17:20:45 - [nodemon] to restart at any time, enter `rs`
3 Apr 17:20:45 - [nodemon] watching: *.*
3 Apr 17:20:45 - [nodemon] starting `node ./scripts/www.js`
##############################################################
#
# !!! MONGOOSE WARNING !!!
#
# This is an UNSTABLE release of Mongoose.
# Unstable releases are available for preview/testing only.
# DO NOT run this in production.
#
##############################################################
GuestbookLiteCatalog db opened
GuestbookLiteCatalog db seeded
C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\base.js:246
throw message;
^
TypeError: Cannot read property 'length' of undefined
at processResults (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\db.js:1581:31)
at C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\db.js:1619:20
at C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\db.js:1157:7
at C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\db.js:1890:9
at Server.Base._callHandler (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\base.js:448:41)
at C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\server.js:481:18
at MongoReply.parseBody (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\responses\mongo_reply.js:68:5)
at null.<anonymous> (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\server.js:439:20)
at emit (events.js:95:17)
at null.<anonymous> (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\connection_pool.js:201:13)
3 Apr 17:20:45 - [nodemon] app crashed - waiting for file changes before starting...
导致问题的代码块是下面for循环中的迭代器...
/**
* Retrieves this collections index info.
*
* Options
* - **full** {Boolean, default:false}, returns the full raw index information.
* - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
*
* @param {String} collectionName the name of the collection.
* @param {Object} [options] additional options during update.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occurred, or null otherwise. While the second parameter will contain the results from indexInformation or null if an error occurred.
* @return {null}
* @api public
*/
Db.prototype.indexInformation = function(name, options, callback) {
if(typeof callback === 'undefined') {
if(typeof options === 'undefined') {
callback = name;
name = null;
} else {
callback = options;
}
options = {};
}
// Throw is no name provided
if(name == null) throw new Error("A collection name must be provided as first argument");
// If we specified full information
var full = options['full'] == null ? false : options['full'];
var self = this;
// Process all the results from the index command and collection
var processResults = function(indexes) {
// Contains all the information
var info = {};
// Process all the indexes
if (indexes) {
for(var i = 0; i < indexes.length; i++) {
var index = indexes[i];
// Let's unpack the object
info[index.name] = [];
for(var name in index.key) {
info[index.name].push([name, index.key[name]]);
}
}
}
return info;
}
// Fallback to pre 2.8 getting the index information
var fallbackListIndexes = function() {
// Build selector for the indexes
var selector = name != null ? {ns: (self.databaseName + "." + name)} : {};
// Get read preference if we set one
var readPreference = ReadPreference.PRIMARY;
// Iterate through all the fields of the index
var collection = self.collection(DbCommand.SYSTEM_INDEX_COLLECTION);
// Perform the find for the collection
collection.find(selector).setReadPreference(readPreference).toArray(function(err, indexes) {
if(err != null) return callback(err, null);
// if full defined just return all the indexes directly
if(full) return callback(null, indexes);
// Return all the indexes
callback(null, processResults(indexes));
});
}
// Attempt to execute the listIndexes command
self.command({listIndexes: name}, function(err, result) {
if(err) return fallbackListIndexes();
// if full defined just return all the indexes directly
if(full) return callback(null, result.indexes);
// Return all the indexes
callback(null, processResults(result.indexes));
});
};
加载第一个模型后,一旦应用程序初始化就会抛出异常。这是其中之一...
/*jslint node: true, nomen: true, es5: true */
/**
* Generated by Fred Lackey <fred.lackey@spotless.cc> on 4/3/2015 5:03:44 PM
* Copyright 2015 Fred Lackey
* Direct questions to the author: Fred Lackey <fred.lackey@gmail.com>
*/
'use strict';
var arrays = require('dzutils').arrays,
async = require('async'),
booleans = require('dzutils').booleans,
dates = require('dzutils').dates,
moment = require('moment'),
mongoose = require('mongoose'),
numbers = require('dzutils').numbers,
strings = require('dzutils').strings,
uids = require('dzutils').uuids,
util = require('util');
var eventSchema = new mongoose.Schema({
_id: { type: String, trim: true, uppercase: true, default: uids.newIdentifier, validate: [uids.isIdentifier, '_id (id) is not a valid identifier'], required: true },
nm: { type: String, trim: true, validate: [strings.isValidString, 'nm (name) is not a valid string'], required: true },
clientName: { type: String, trim: true, validate: [strings.isValidString, 'clientName is not a valid string'], required: true },
_v: { type: Date, validate: [dates.isDate, '_v (auditVersionDate) is not a valid date'], required: true },
_m: { type: String, trim: true, uppercase: true, validate: [uids.isIdentifier, '_m (auditMemberUid) is not a valid identifier'], required: true },
_k: { type: Date, default: null, validate: [dates.isDateOrNull, '_k (auditDeletedDate) is not a valid date or null value'], required: false }
});
eventSchema.index({
nm: 1,
clientName: 1,
_k: 1
}, { unique: true });
var validateItem = function (item) {
if (!item) { return 'No item to validate'; }
if (typeof item._id !== 'undefined') { if (!uids.isIdentifier(item._id)) { return '_id (id) is not a valid String'; } else { item._id = strings.trimToNull(item._id); } }
if (typeof item.nm !== 'undefined') { if (!strings.isValidString(item.nm)) { return 'nm (name) is not a valid String'; } else { item.nm = strings.trimToNull(item.nm); } }
if (typeof item.clientName !== 'undefined') { if (!strings.isValidString(item.clientName)) { return 'clientName is not a valid String'; } else { item.clientName = strings.trimToNull(item.clientName); } }
if (typeof item._v !== 'undefined') { if (!dates.isDate(item._v)) { return '_v (auditVersionDate) is not a valid Date'; } }
if (typeof item._m !== 'undefined') { if (!uids.isIdentifier(item._m)) { return '_m (auditMemberUid) is not a valid String'; } else { item._m = strings.trimToNull(item._m); } }
if (typeof item._k !== 'undefined') { if (!dates.isDateOrNull(item._k)) { return '_k (auditDeletedDate) is not a valid Date or null value'; } }
return null;
};
eventSchema.methods.validateItem = validateItem;
var validateItems = function (items) {
if (arrays.count(items) < 1) { return null; }
var i, err;
for (i = 0; i < items.length; i += 1) {
err = validateItem(items(i));
if (err){ return 'Item ' + i + ' error: ' + err; }
}
return null;
};
eventSchema.methods.validateItems = validateItems;
var toDto = function (item) {
if (!item) { return null; }
var dto = {};
if (typeof item._id !== 'undefined') { dto.id = item._id; }
if (typeof item.nm !== 'undefined') { dto.nm = item.nm; }
if (typeof item.clientName !== 'undefined') { dto.clientName = item.clientName; }
if (typeof item._v !== 'undefined') { dto.v = item._v; }
if (typeof item._m !== 'undefined') { dto.m = item._m; }
if (typeof item._k !== 'undefined') { dto.k = item._k; }
return dto;
};
eventSchema.methods.toDto = toDto;
var toDtos = function (items) {
if (arrays.count(items) < 1) { return null; }
var i, dtos = [];
for (i = 0; i < items.length; i += 1) {
dtos.push(toDto(items[i]));
}
return dtos;
};
eventSchema.methods.toDto = toDto;
var toDtoFull = function (item) {
if (!item) { return null; }
var dto = {
id: ((typeof item._id !== 'undefined') ? item._id : null),
nm: ((typeof item.nm !== 'undefined') ? item.nm : null),
clientName: ((typeof item.clientName !== 'undefined') ? item.clientName : null),
v: ((typeof item._v !== 'undefined') ? item._v : null),
m: ((typeof item._m !== 'undefined') ? item._m : null),
k: ((typeof item._k !== 'undefined') ? item._k : null)
};
return dto;
};
eventSchema.methods.toDtoFull = toDtoFull;
var toDtosFull = function (items) {
if (arrays.count(items) < 1) { return null; }
var i, dtos = [];
for (i = 0; i < items.length; i += 1) {
dtos.push(toDtoFull(items[i]));
}
return dtos;
};
eventSchema.methods.toDtosFull = toDtosFull;
var toItem = function (dto) {
if (!dto) { return null; }
var item = {};
if (typeof dto.id !== 'undefined') { item._id = dto.id; }
if (typeof dto.nm !== 'undefined') { item.nm = dto.nm; }
if (typeof dto.clientName !== 'undefined') { item.clientName = dto.clientName; }
if (typeof dto.v !== 'undefined') { item._v = dto.v; }
if (typeof dto.m !== 'undefined') { item._m = dto.m; }
if (typeof dto.k !== 'undefined') { item._k = dto.k; }
return item;
};
eventSchema.methods.toItem = toItem;
var toItems = function toItems(dtos) {
if (arrays.count(dtos) < 1) { return null; }
var i, items = [];
for (i = 0; i < dtos.length; i += 1) {
items.push(toItem(dtos[i]));
}
return items;
};
eventSchema.methods.toItems = toItems;
var toItemFull = function toItemFull(dto) {
if (!dto) { return null; }
var item = {
_id: ((typeof dto.id !== 'undefined') ? dto.id : null),
nm: ((typeof dto.nm !== 'undefined') ? dto.nm : null),
clientName: ((typeof dto.clientName !== 'undefined') ? dto.clientName : null),
_v: ((typeof dto.v !== 'undefined') ? dto.v : null),
_m: ((typeof dto.m !== 'undefined') ? dto.m : null),
_k: ((typeof dto.k !== 'undefined') ? dto.k : null)
};
return item;
};
eventSchema.methods.toItemFull = toItemFull;
var toItemsFull = function (dtos) {
if (arrays.count(dtos) < 1) { return null; }
var i, items = [];
for (i = 0; i < dtos.length; i += 1) {
items.push(toItemFull(dtos[i]));
}
return items;
};
eventSchema.methods.toItemsFull = toItemsFull;
var filterUnique = function (array) {
if (arrays.count(array) < 1) { return null; }
var a, r, found, result = [];
for (a = 0; a < array.length; a += 1) {
if (typeof array[a].id !== 'undefined') {
found = false;
for (r = 0; r < result.length; r += 1) {
if (result[r].id === array[a].id) {
found = true;
break;
}
}
if (found === false) { result.push(array[a]); }
}
}
return result;
};
eventSchema.methods.filterUnique = filterUnique;
var getAll = function (callback) {
var query = { _k: null };
mongoose.model('Event').find(query, function (err, items) {
if (err) { return callback(err); }
return callback(null, toDtos(items));
});
};
eventSchema.methods.getAll = getAll;
var getById = function (id, callback) {
var query = { _id: id, _k: null };
var err = validateItem(query);
if (err) { return callback(new Error(err)); }
mongoose.model('Event').findOne(query, function (err, item) {
if (err) { return callback(err); }
if (item) { return callback(null, toDto(item)); }
return callback();
});
};
eventSchema.methods.getById = getById;
var getByIds = function (ids, callback) {
if (!util.isArray(ids)){ return callback(new Error('ids is not an array')); }
var query = { _id: { $in: ids }, _k: null };
mongoose.model('Event').find(query, function (err, items) {
if (err) { return callback(err); }
if (items) { return callback(null, toDtos(items)); }
return callback();
});
};
eventSchema.methods.getByIds = getByIds;
var getOneByNameClientName = function (name, clientName, callback) {
var query = {
nm: name,
clientName: clientName,
_k: null
};
var err = validateItem(query);
if (err) { return callback(new Error(err)); }
mongoose.model('Event').findOne(query, function (err, item) {
if (err) { return callback(err); }
if (item) { return callback(null, toDto(item)); }
return callback();
});
};
eventSchema.methods.getOneByNameClientName = getOneByNameClientName;
var getOneByNameClientNameMany = function (queries, callback) {
if (!queries || !util.isArray(queries)) { return callback(new Error('Invalid query array')); }
if (queries.length < 1) { return callback(); }
var result = [];
async.forEach(queries, function (query, next){
getOneByNameClientName(query.name, query.clientName, function (err, item) {
if (err) {
return callback(new Error('Error on #' + result.length + ': ' + err.message));
} else {
result.push(item);
}
next();
});
}, function (err) {
if (err) {
return callback(err);
} else {
return callback(null, filterUnique(result));
}
});
};
eventSchema.methods.getOneByNameClientNameMany = getOneByNameClientNameMany;
var createNew = function (name, clientName, auditMemberUid, callback) {
var data = {
nm: name,
clientName: clientName,
_v: new Date(),
_m: auditMemberUid,
_k: null
};
var err = validateItem(data);
if (err) { return callback(new Error(err)); }
var newItem = new Event(data);
newItem.save(function (err, item) {
if (err) { return callback(err); }
return callback(null, toDto(item));
});
};
eventSchema.methods.createNew = createNew;
var createNewMany = function (items, callback) {
if (!items || !util.isArray(items)) { return callback(new Error('Invalid item array')); }
if (items.length < 1) { return callback(); }
var ids = [];
async.forEach(items, function (item, next){
createNew(item.name, item.clientName, item.auditMemberUid, function (err, id) {
if (err) {
return callback(new Error('Error on #' + ids.length + ': ' + err.message));
} else {
ids.push(id);
}
next();
});
}, function (err) {
if (err) {
return callback(err);
} else {
return callback(null, ids);
}
});
};
eventSchema.methods.createNewMany = createNewMany;
var createNewOrGet = function (name, clientName, auditMemberUid, suppressError, callback) {
var dupErr = suppressError ? null : (new Error('Duplicate Event detected'));
getOneByNameClientName(name, clientName, function (err, existing) {
if (err) { return callback(err); }
if (existing) { return callback(dupErr, existing); }
return createNew(name, clientName, auditMemberUid, callback);
});
};
eventSchema.methods.createNewOrGet = createNewOrGet;
var getCount = function (includeDeleted, callback) {
var query = {};
if (includeDeleted !== true) { query._k = null; }
return mongoose.model('Event').count(query, callback);
};
eventSchema.methods.getCount = getCount;
var getCountByQuery = function (queryDto, callback) {
var query = toItem(queryDto);
var err = validateItem(query);
if (err) { return callback(new Error('Invalid query: ' + err)); }
mongoose.model('Event').count(query, callback);
};
eventSchema.methods.getCountByQuery = getCountByQuery;
var modifyMany = function (queryDto, updateDto, auditMemberUid, callback) {
if (typeof queryDto === 'undefined') { return callback(new Error('No query supplied')); }
if (typeof updateDto === 'undefined') { return callback(new Error('No Update Supplied')); }
if (typeof auditMemberUid === 'undefined') { return callback(new Error('No auditMemberUid supplied')); }
queryDto.auditDeletedDate = null;
updateDto.auditVersionDate = moment().utc().toDate();
updateDto.auditMemberUid = auditMemberUid;
var query = toItem(queryDto),
update = toItem(updateDto);
var err = validateItem(query);
if (err) { return callback(new Error('Invalid query: ' + err)); }
err = validateItem(update);
if (err) { return callback(new Error('Invalid update: ' + err)); }
return mongoose.model('Event').update(query, update, callback);
};
eventSchema.methods.modifyMany = modifyMany;
var modifyOne = function (queryDto, updateDto, auditMemberUid, callback) {
if (typeof queryDto === 'undefined') { return callback(new Error('No query supplied')); }
if (typeof updateDto === 'undefined') { return callback(new Error('No Update Supplied')); }
if (typeof auditMemberUid === 'undefined') { return callback(new Error('No auditMemberUid supplied')); }
queryDto.auditDeletedDate = null;
updateDto.auditVersionDate = moment().utc().toDate();
updateDto.auditMemberUid = auditMemberUid;
var query = toItem(queryDto),
update = toItem(updateDto);
var err = validateItem(query);
if (err) { return callback(new Error('Invalid query: ' + err)); }
err = validateItem(update);
if (err) { return callback(new Error('Invalid update: ' + err)); }
mongoose.model('Event').findOneAndUpdate(query, update, function (err, item) {
if (err) { return callback(err); }
if (item) { return callback(null, toDto(item)); }
return callback();
});
};
eventSchema.methods.modifyOne = modifyOne;
var deleteMany = function (queryDto, auditMemberUid, callback) {
if (typeof queryDto === 'undefined') { return callback(new Error('No query supplied')); }
queryDto.auditDeletedDate = null;
var updateDto = { auditDeletedDate: moment().utc().toDate() };
return modifyMany(queryDto, updateDto, auditMemberUid, callback);
};
eventSchema.methods.deleteMany = deleteMany;
var deleteOne = function (queryDto, auditMemberUid, callback) {
if (typeof queryDto === 'undefined') { return callback(new Error('No query supplied')); }
var updateDto = { auditDeletedDate: moment().utc().toDate() };
return modifyOne(queryDto, updateDto, auditMemberUid, callback);
};
eventSchema.methods.deleteOne = deleteOne;
var Event = mongoose.model('Event', eventSchema);
module.exports = Event;
中间数字为奇数的 Mongoose 版本(如 3.9.7)不稳定,不应在生产中使用(在 3.7.0 release notes 中提到)。
我在 3.8.23 和 4.0.1 Mongoose 版本中尝试了您的事件模型定义代码,它在这两种情况下都运行良好,clientName
和 nm
上的索引按定义创建在架构中。
完整项目位置:
http://github.com/FredLackey/...
有没有人看到下面的异常?知道如何度过难关吗?我的模型确实有索引,所以我能想到没有理由不存在索引。
MongoDB 客户端代码在 Mongoose 中抛出异常...
C:\_\GuestbookLite\Projects\GuestbookLiteCatalog>npm start
> GuestbookLiteCatalog@0.1.0 start C:\_\GuestbookLite\Projects\GuestbookLiteCatalog
> nodemon ./scripts/www.js
3 Apr 17:20:45 - [nodemon] v1.3.7
3 Apr 17:20:45 - [nodemon] to restart at any time, enter `rs`
3 Apr 17:20:45 - [nodemon] watching: *.*
3 Apr 17:20:45 - [nodemon] starting `node ./scripts/www.js`
##############################################################
#
# !!! MONGOOSE WARNING !!!
#
# This is an UNSTABLE release of Mongoose.
# Unstable releases are available for preview/testing only.
# DO NOT run this in production.
#
##############################################################
GuestbookLiteCatalog db opened
GuestbookLiteCatalog db seeded
C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\base.js:246
throw message;
^
TypeError: Cannot read property 'length' of undefined
at processResults (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\db.js:1581:31)
at C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\db.js:1619:20
at C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\db.js:1157:7
at C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\db.js:1890:9
at Server.Base._callHandler (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\base.js:448:41)
at C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\server.js:481:18
at MongoReply.parseBody (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\responses\mongo_reply.js:68:5)
at null.<anonymous> (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\server.js:439:20)
at emit (events.js:95:17)
at null.<anonymous> (C:\_\GuestbookLite\Projects\GuestbookLiteCatalog\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\connection_pool.js:201:13)
3 Apr 17:20:45 - [nodemon] app crashed - waiting for file changes before starting...
导致问题的代码块是下面for循环中的迭代器...
/**
* Retrieves this collections index info.
*
* Options
* - **full** {Boolean, default:false}, returns the full raw index information.
* - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
*
* @param {String} collectionName the name of the collection.
* @param {Object} [options] additional options during update.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occurred, or null otherwise. While the second parameter will contain the results from indexInformation or null if an error occurred.
* @return {null}
* @api public
*/
Db.prototype.indexInformation = function(name, options, callback) {
if(typeof callback === 'undefined') {
if(typeof options === 'undefined') {
callback = name;
name = null;
} else {
callback = options;
}
options = {};
}
// Throw is no name provided
if(name == null) throw new Error("A collection name must be provided as first argument");
// If we specified full information
var full = options['full'] == null ? false : options['full'];
var self = this;
// Process all the results from the index command and collection
var processResults = function(indexes) {
// Contains all the information
var info = {};
// Process all the indexes
if (indexes) {
for(var i = 0; i < indexes.length; i++) {
var index = indexes[i];
// Let's unpack the object
info[index.name] = [];
for(var name in index.key) {
info[index.name].push([name, index.key[name]]);
}
}
}
return info;
}
// Fallback to pre 2.8 getting the index information
var fallbackListIndexes = function() {
// Build selector for the indexes
var selector = name != null ? {ns: (self.databaseName + "." + name)} : {};
// Get read preference if we set one
var readPreference = ReadPreference.PRIMARY;
// Iterate through all the fields of the index
var collection = self.collection(DbCommand.SYSTEM_INDEX_COLLECTION);
// Perform the find for the collection
collection.find(selector).setReadPreference(readPreference).toArray(function(err, indexes) {
if(err != null) return callback(err, null);
// if full defined just return all the indexes directly
if(full) return callback(null, indexes);
// Return all the indexes
callback(null, processResults(indexes));
});
}
// Attempt to execute the listIndexes command
self.command({listIndexes: name}, function(err, result) {
if(err) return fallbackListIndexes();
// if full defined just return all the indexes directly
if(full) return callback(null, result.indexes);
// Return all the indexes
callback(null, processResults(result.indexes));
});
};
加载第一个模型后,一旦应用程序初始化就会抛出异常。这是其中之一...
/*jslint node: true, nomen: true, es5: true */
/**
* Generated by Fred Lackey <fred.lackey@spotless.cc> on 4/3/2015 5:03:44 PM
* Copyright 2015 Fred Lackey
* Direct questions to the author: Fred Lackey <fred.lackey@gmail.com>
*/
'use strict';
var arrays = require('dzutils').arrays,
async = require('async'),
booleans = require('dzutils').booleans,
dates = require('dzutils').dates,
moment = require('moment'),
mongoose = require('mongoose'),
numbers = require('dzutils').numbers,
strings = require('dzutils').strings,
uids = require('dzutils').uuids,
util = require('util');
var eventSchema = new mongoose.Schema({
_id: { type: String, trim: true, uppercase: true, default: uids.newIdentifier, validate: [uids.isIdentifier, '_id (id) is not a valid identifier'], required: true },
nm: { type: String, trim: true, validate: [strings.isValidString, 'nm (name) is not a valid string'], required: true },
clientName: { type: String, trim: true, validate: [strings.isValidString, 'clientName is not a valid string'], required: true },
_v: { type: Date, validate: [dates.isDate, '_v (auditVersionDate) is not a valid date'], required: true },
_m: { type: String, trim: true, uppercase: true, validate: [uids.isIdentifier, '_m (auditMemberUid) is not a valid identifier'], required: true },
_k: { type: Date, default: null, validate: [dates.isDateOrNull, '_k (auditDeletedDate) is not a valid date or null value'], required: false }
});
eventSchema.index({
nm: 1,
clientName: 1,
_k: 1
}, { unique: true });
var validateItem = function (item) {
if (!item) { return 'No item to validate'; }
if (typeof item._id !== 'undefined') { if (!uids.isIdentifier(item._id)) { return '_id (id) is not a valid String'; } else { item._id = strings.trimToNull(item._id); } }
if (typeof item.nm !== 'undefined') { if (!strings.isValidString(item.nm)) { return 'nm (name) is not a valid String'; } else { item.nm = strings.trimToNull(item.nm); } }
if (typeof item.clientName !== 'undefined') { if (!strings.isValidString(item.clientName)) { return 'clientName is not a valid String'; } else { item.clientName = strings.trimToNull(item.clientName); } }
if (typeof item._v !== 'undefined') { if (!dates.isDate(item._v)) { return '_v (auditVersionDate) is not a valid Date'; } }
if (typeof item._m !== 'undefined') { if (!uids.isIdentifier(item._m)) { return '_m (auditMemberUid) is not a valid String'; } else { item._m = strings.trimToNull(item._m); } }
if (typeof item._k !== 'undefined') { if (!dates.isDateOrNull(item._k)) { return '_k (auditDeletedDate) is not a valid Date or null value'; } }
return null;
};
eventSchema.methods.validateItem = validateItem;
var validateItems = function (items) {
if (arrays.count(items) < 1) { return null; }
var i, err;
for (i = 0; i < items.length; i += 1) {
err = validateItem(items(i));
if (err){ return 'Item ' + i + ' error: ' + err; }
}
return null;
};
eventSchema.methods.validateItems = validateItems;
var toDto = function (item) {
if (!item) { return null; }
var dto = {};
if (typeof item._id !== 'undefined') { dto.id = item._id; }
if (typeof item.nm !== 'undefined') { dto.nm = item.nm; }
if (typeof item.clientName !== 'undefined') { dto.clientName = item.clientName; }
if (typeof item._v !== 'undefined') { dto.v = item._v; }
if (typeof item._m !== 'undefined') { dto.m = item._m; }
if (typeof item._k !== 'undefined') { dto.k = item._k; }
return dto;
};
eventSchema.methods.toDto = toDto;
var toDtos = function (items) {
if (arrays.count(items) < 1) { return null; }
var i, dtos = [];
for (i = 0; i < items.length; i += 1) {
dtos.push(toDto(items[i]));
}
return dtos;
};
eventSchema.methods.toDto = toDto;
var toDtoFull = function (item) {
if (!item) { return null; }
var dto = {
id: ((typeof item._id !== 'undefined') ? item._id : null),
nm: ((typeof item.nm !== 'undefined') ? item.nm : null),
clientName: ((typeof item.clientName !== 'undefined') ? item.clientName : null),
v: ((typeof item._v !== 'undefined') ? item._v : null),
m: ((typeof item._m !== 'undefined') ? item._m : null),
k: ((typeof item._k !== 'undefined') ? item._k : null)
};
return dto;
};
eventSchema.methods.toDtoFull = toDtoFull;
var toDtosFull = function (items) {
if (arrays.count(items) < 1) { return null; }
var i, dtos = [];
for (i = 0; i < items.length; i += 1) {
dtos.push(toDtoFull(items[i]));
}
return dtos;
};
eventSchema.methods.toDtosFull = toDtosFull;
var toItem = function (dto) {
if (!dto) { return null; }
var item = {};
if (typeof dto.id !== 'undefined') { item._id = dto.id; }
if (typeof dto.nm !== 'undefined') { item.nm = dto.nm; }
if (typeof dto.clientName !== 'undefined') { item.clientName = dto.clientName; }
if (typeof dto.v !== 'undefined') { item._v = dto.v; }
if (typeof dto.m !== 'undefined') { item._m = dto.m; }
if (typeof dto.k !== 'undefined') { item._k = dto.k; }
return item;
};
eventSchema.methods.toItem = toItem;
var toItems = function toItems(dtos) {
if (arrays.count(dtos) < 1) { return null; }
var i, items = [];
for (i = 0; i < dtos.length; i += 1) {
items.push(toItem(dtos[i]));
}
return items;
};
eventSchema.methods.toItems = toItems;
var toItemFull = function toItemFull(dto) {
if (!dto) { return null; }
var item = {
_id: ((typeof dto.id !== 'undefined') ? dto.id : null),
nm: ((typeof dto.nm !== 'undefined') ? dto.nm : null),
clientName: ((typeof dto.clientName !== 'undefined') ? dto.clientName : null),
_v: ((typeof dto.v !== 'undefined') ? dto.v : null),
_m: ((typeof dto.m !== 'undefined') ? dto.m : null),
_k: ((typeof dto.k !== 'undefined') ? dto.k : null)
};
return item;
};
eventSchema.methods.toItemFull = toItemFull;
var toItemsFull = function (dtos) {
if (arrays.count(dtos) < 1) { return null; }
var i, items = [];
for (i = 0; i < dtos.length; i += 1) {
items.push(toItemFull(dtos[i]));
}
return items;
};
eventSchema.methods.toItemsFull = toItemsFull;
var filterUnique = function (array) {
if (arrays.count(array) < 1) { return null; }
var a, r, found, result = [];
for (a = 0; a < array.length; a += 1) {
if (typeof array[a].id !== 'undefined') {
found = false;
for (r = 0; r < result.length; r += 1) {
if (result[r].id === array[a].id) {
found = true;
break;
}
}
if (found === false) { result.push(array[a]); }
}
}
return result;
};
eventSchema.methods.filterUnique = filterUnique;
var getAll = function (callback) {
var query = { _k: null };
mongoose.model('Event').find(query, function (err, items) {
if (err) { return callback(err); }
return callback(null, toDtos(items));
});
};
eventSchema.methods.getAll = getAll;
var getById = function (id, callback) {
var query = { _id: id, _k: null };
var err = validateItem(query);
if (err) { return callback(new Error(err)); }
mongoose.model('Event').findOne(query, function (err, item) {
if (err) { return callback(err); }
if (item) { return callback(null, toDto(item)); }
return callback();
});
};
eventSchema.methods.getById = getById;
var getByIds = function (ids, callback) {
if (!util.isArray(ids)){ return callback(new Error('ids is not an array')); }
var query = { _id: { $in: ids }, _k: null };
mongoose.model('Event').find(query, function (err, items) {
if (err) { return callback(err); }
if (items) { return callback(null, toDtos(items)); }
return callback();
});
};
eventSchema.methods.getByIds = getByIds;
var getOneByNameClientName = function (name, clientName, callback) {
var query = {
nm: name,
clientName: clientName,
_k: null
};
var err = validateItem(query);
if (err) { return callback(new Error(err)); }
mongoose.model('Event').findOne(query, function (err, item) {
if (err) { return callback(err); }
if (item) { return callback(null, toDto(item)); }
return callback();
});
};
eventSchema.methods.getOneByNameClientName = getOneByNameClientName;
var getOneByNameClientNameMany = function (queries, callback) {
if (!queries || !util.isArray(queries)) { return callback(new Error('Invalid query array')); }
if (queries.length < 1) { return callback(); }
var result = [];
async.forEach(queries, function (query, next){
getOneByNameClientName(query.name, query.clientName, function (err, item) {
if (err) {
return callback(new Error('Error on #' + result.length + ': ' + err.message));
} else {
result.push(item);
}
next();
});
}, function (err) {
if (err) {
return callback(err);
} else {
return callback(null, filterUnique(result));
}
});
};
eventSchema.methods.getOneByNameClientNameMany = getOneByNameClientNameMany;
var createNew = function (name, clientName, auditMemberUid, callback) {
var data = {
nm: name,
clientName: clientName,
_v: new Date(),
_m: auditMemberUid,
_k: null
};
var err = validateItem(data);
if (err) { return callback(new Error(err)); }
var newItem = new Event(data);
newItem.save(function (err, item) {
if (err) { return callback(err); }
return callback(null, toDto(item));
});
};
eventSchema.methods.createNew = createNew;
var createNewMany = function (items, callback) {
if (!items || !util.isArray(items)) { return callback(new Error('Invalid item array')); }
if (items.length < 1) { return callback(); }
var ids = [];
async.forEach(items, function (item, next){
createNew(item.name, item.clientName, item.auditMemberUid, function (err, id) {
if (err) {
return callback(new Error('Error on #' + ids.length + ': ' + err.message));
} else {
ids.push(id);
}
next();
});
}, function (err) {
if (err) {
return callback(err);
} else {
return callback(null, ids);
}
});
};
eventSchema.methods.createNewMany = createNewMany;
var createNewOrGet = function (name, clientName, auditMemberUid, suppressError, callback) {
var dupErr = suppressError ? null : (new Error('Duplicate Event detected'));
getOneByNameClientName(name, clientName, function (err, existing) {
if (err) { return callback(err); }
if (existing) { return callback(dupErr, existing); }
return createNew(name, clientName, auditMemberUid, callback);
});
};
eventSchema.methods.createNewOrGet = createNewOrGet;
var getCount = function (includeDeleted, callback) {
var query = {};
if (includeDeleted !== true) { query._k = null; }
return mongoose.model('Event').count(query, callback);
};
eventSchema.methods.getCount = getCount;
var getCountByQuery = function (queryDto, callback) {
var query = toItem(queryDto);
var err = validateItem(query);
if (err) { return callback(new Error('Invalid query: ' + err)); }
mongoose.model('Event').count(query, callback);
};
eventSchema.methods.getCountByQuery = getCountByQuery;
var modifyMany = function (queryDto, updateDto, auditMemberUid, callback) {
if (typeof queryDto === 'undefined') { return callback(new Error('No query supplied')); }
if (typeof updateDto === 'undefined') { return callback(new Error('No Update Supplied')); }
if (typeof auditMemberUid === 'undefined') { return callback(new Error('No auditMemberUid supplied')); }
queryDto.auditDeletedDate = null;
updateDto.auditVersionDate = moment().utc().toDate();
updateDto.auditMemberUid = auditMemberUid;
var query = toItem(queryDto),
update = toItem(updateDto);
var err = validateItem(query);
if (err) { return callback(new Error('Invalid query: ' + err)); }
err = validateItem(update);
if (err) { return callback(new Error('Invalid update: ' + err)); }
return mongoose.model('Event').update(query, update, callback);
};
eventSchema.methods.modifyMany = modifyMany;
var modifyOne = function (queryDto, updateDto, auditMemberUid, callback) {
if (typeof queryDto === 'undefined') { return callback(new Error('No query supplied')); }
if (typeof updateDto === 'undefined') { return callback(new Error('No Update Supplied')); }
if (typeof auditMemberUid === 'undefined') { return callback(new Error('No auditMemberUid supplied')); }
queryDto.auditDeletedDate = null;
updateDto.auditVersionDate = moment().utc().toDate();
updateDto.auditMemberUid = auditMemberUid;
var query = toItem(queryDto),
update = toItem(updateDto);
var err = validateItem(query);
if (err) { return callback(new Error('Invalid query: ' + err)); }
err = validateItem(update);
if (err) { return callback(new Error('Invalid update: ' + err)); }
mongoose.model('Event').findOneAndUpdate(query, update, function (err, item) {
if (err) { return callback(err); }
if (item) { return callback(null, toDto(item)); }
return callback();
});
};
eventSchema.methods.modifyOne = modifyOne;
var deleteMany = function (queryDto, auditMemberUid, callback) {
if (typeof queryDto === 'undefined') { return callback(new Error('No query supplied')); }
queryDto.auditDeletedDate = null;
var updateDto = { auditDeletedDate: moment().utc().toDate() };
return modifyMany(queryDto, updateDto, auditMemberUid, callback);
};
eventSchema.methods.deleteMany = deleteMany;
var deleteOne = function (queryDto, auditMemberUid, callback) {
if (typeof queryDto === 'undefined') { return callback(new Error('No query supplied')); }
var updateDto = { auditDeletedDate: moment().utc().toDate() };
return modifyOne(queryDto, updateDto, auditMemberUid, callback);
};
eventSchema.methods.deleteOne = deleteOne;
var Event = mongoose.model('Event', eventSchema);
module.exports = Event;
中间数字为奇数的 Mongoose 版本(如 3.9.7)不稳定,不应在生产中使用(在 3.7.0 release notes 中提到)。
我在 3.8.23 和 4.0.1 Mongoose 版本中尝试了您的事件模型定义代码,它在这两种情况下都运行良好,clientName
和 nm
上的索引按定义创建在架构中。