0
這是我的歌曲模式。 忽略import語句使用貓鼬保存引用對象的問題
var SongSchema = new mongoose.Schema({
name: String,
genre: String,
artist: String,
album: String,
year: Number,
composer: String,
lyrics: String,
duration: Number // [seconds]
});
var Song = module.exports = mongoose.model('Song', SongSchema);
這是我的播放列表模式
var PlaylistSchema = new mongoose.Schema({
name: String,
genre: String,
songs: [{
details: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Song'
},
upvote_count: Number,
state: String,
type: String
}]
});
var Playlist = mongoose.model("Playlist", PlaylistSchema);
錯誤代碼:使用上面的代碼我收到以下錯誤保存該播放列表
console.log("object:", song.details);
var newSong = new Song(song.details);
newSong.save();
console.log("song:", newSong);
newPlaylist.songs.push({
details: newSong._id,
upvote_count: song.upvote_count || 0,
state: song.state || SongState.QUEUED,
type: song.type || SongType.NOT_FROZEN
});
,
object: { name: 'String',
genre: 'String',
artist: 'String',
album: 'String',
year: 2010,
composer: 'String',
lyrics: 'String' }
song: strictMode=true, selected=undefined, shardval=undefined, saveError=undefined, validationError=undefined, adhocPaths=undefined, removing=undefined, inserting=undefined, version=undefined, , _id=undefined, populate=undefined, populated=undefined, wasPopulated=false, scope=undefined, _id=default, duration=modify, lyrics=modify, composer=modify, year=modify, album=modify, artist=modify, genre=modify, name=modify, , _id=true, , duration=true, lyrics=true, composer=true, year=true, album=true, artist=true, genre=true, name=true, , stateNames=[require, modify, init, default, ignore], ownerDocument=undefined, fullPath=undefined, domain=null, , _maxListeners=0, isNew=true, errors=undefined, _bsontype=ObjectID, id=VSriÆùá÷%ß8, duration=42, lyrics=, composer=, year=2015, album=, artist=, genre=, name=, $__original_save=function() {
var self = this
, hookArgs // arguments eventually passed to the hook - are mutable
, lastArg = arguments[arguments.length-1]
, pres = this._pres[name]
, posts = this._posts[name]
, _total = pres.length
, _current = -1
, _asyncsLeft = proto[name].numAsyncPres
, _asyncsDone = function(err) {
if (err) {
return handleError(err);
}
--_asyncsLeft || _done.apply(self, hookArgs);
}
, handleError = function(err) {
if ('function' == typeof lastArg)
return lastArg(err);
if (errorCb) return errorCb.call(self, err);
throw err;
}
, _next = function() {
if (arguments[0] instanceof Error) {
return handleError(arguments[0]);
}
var _args = Array.prototype.slice.call(arguments)
, currPre
, preArgs;
if (_args.length && !(arguments[0] == null && typeof lastArg === 'function'))
hookArgs = _args;
if (++_current < _total) {
currPre = pres[_current]
if (currPre.isAsync && currPre.length < 2)
throw new Error("Your pre must have next and done arguments -- e.g., function (next, done, ...)");
if (currPre.length < 1)
throw new Error("Your pre must have a next argument -- e.g., function (next, ...)");
preArgs = (currPre.isAsync
? [once(_next), once(_asyncsDone)]
: [once(_next)]).concat(hookArgs);
return currPre.apply(self, preArgs);
} else if (!_asyncsLeft) {
return _done.apply(self, hookArgs);
}
}
, _done = function() {
var args_ = Array.prototype.slice.call(arguments)
, ret, total_, current_, next_, done_, postArgs;
if (_current === _total) {
next_ = function() {
if (arguments[0] instanceof Error) {
return handleError(arguments[0]);
}
var args_ = Array.prototype.slice.call(arguments, 1)
, currPost
, postArgs;
if (args_.length) hookArgs = args_;
if (++current_ < total_) {
currPost = posts[current_]
if (currPost.length < 1)
throw new Error("Your post must have a next argument -- e.g., function (next, ...)");
postArgs = [once(next_)].concat(hookArgs);
return currPost.apply(self, postArgs);
} else if (typeof lastArg === 'function'){
// All post handlers are done, call original callback function
return lastArg.apply(self, arguments);
}
};
// We are assuming that if the last argument provided to the wrapped function is a function, it was expecting
// a callback. We trap that callback and wait to call it until all post handlers have finished.
if(typeof lastArg === 'function'){
args_[args_.length - 1] = once(next_);
}
total_ = posts.length;
current_ = -1;
ret = fn.apply(self, args_); // Execute wrapped function, post handlers come afterward
if (total_ && typeof lastArg !== 'function') return next_(); // no callback provided, execute next_() manually
return ret;
}
};
return _next.apply(this, arguments);
}, save=function wrappedPointCut() {
var args = [].slice.call(arguments);
var lastArg = args.pop();
var fn;
return new Promise.ES6(function(resolve, reject) {
if (lastArg && typeof lastArg !== 'function') {
args.push(lastArg);
} else {
fn = lastArg;
}
args.push(function(error, result) {
if (error) {
self.$__handleReject(error);
fn && fn(error);
reject(error);
return;
}
fn && fn.apply(null, [null].concat(Array.prototype.slice.call(arguments, 1)));
resolve(result);
});
self[newName].apply(self, args);
});
}, $__original_save=[function (next, options) {
// Nested docs have their own presave
if (this.ownerDocument) {
return next();
}
var hasValidateBeforeSaveOption = options &&
(typeof options === 'object') &&
('validateBeforeSave' in options);
var shouldValidate;
if (hasValidateBeforeSaveOption) {
shouldValidate = !!options.validateBeforeSave;
} else {
shouldValidate = this.schema.options.validateBeforeSave;
}
// Validate
if (shouldValidate) {
// HACK: use $__original_validate to avoid promises so bluebird doesn't
// complain
if (this.$__original_validate) {
this.$__original_validate({ __noPromise: true }, function(error) {
next(error);
});
} else {
this.validate({ __noPromise: true }, function(error) {
next(error);
});
}
} else {
next();
}
}, function (next, done) {
var Promise = PromiseProvider.get(),
subdocs = this.$__getAllSubdocs();
if (!subdocs.length || this.$__preSavingFromParent) {
done();
next();
return;
}
new Promise.ES6(function(resolve, reject) {
async.each(subdocs, function(subdoc, cb) {
subdoc.$__preSavingFromParent = true;
subdoc.save(function(err) {
cb(err);
});
}, function(error) {
for (var i = 0; i < subdocs.length; ++i) {
delete subdocs[i].$__preSavingFromParent;
}
if (error) {
reject(error);
return;
}
resolve();
});
}).then(function() {
next();
done();
}, done);
}], $__original_save=[]
CastError: Cast to string failed for value "[object Object]" at path "songs"
at MongooseError.CastError (/media/D/codebin/grep/node_modules/mongoose/lib/error/cast.js:19:11)
at SchemaString.cast (/media/D/codebin/grep/node_modules/mongoose/lib/schema/string.js:434:9)
at Array.MongooseArray.mixin._cast (/media/D/codebin/grep/node_modules/mongoose/lib/types/array.js:124:32)
at Array.MongooseArray.mixin._mapCast (/media/D/codebin/grep/node_modules/mongoose/lib/types/array.js:295:17)
at Object.map (native)
at Array.MongooseArray.mixin.push (/media/D/codebin/grep/node_modules/mongoose/lib/types/array.js:308:25)
...
如您所見,我保存的newSong具有函數的值。有人可以指出我哪裏錯了。
謝謝@vkarpvov,但我不明白播放列表的模式將如何影響歌曲的保存。我的猜測是返回的對象是一個承諾,但文檔說它應該是保存的對象。 – Tanmay