我有一个项目和用户的架构。我想允许用户喜欢或不喜欢某个项目,我还希望在项目和用户上存储评级关联。
var UserSchema = new Schema({
username : { type: String, required: true, index: { unique: true }
, likes : [{ type: Schema.ObjectId, ref: 'Item'}]
, dislikes : [{ type: Schema.ObjectId, ref: 'Item'}]
, ratings: [???]
});
var ItemSchema = new Schema({
name: { type: String},
, likes : [{ type: Schema.ObjectId, ref: 'User'}]
, dislikes : [{ type: Schema.ObjectId, ref: 'User'}]
, ratings: [???]
});
用户存储项目ref,并且该项目存储用户对于喜欢/不喜欢的参考。我不知道如何将评级作为属性存储,因为我想要用户和他们评价项目的价值。
item.ratings.forEach(function(rating){
<%= rating.user.username %> gave <%= item.name %> a <%= rating.value %>.
});
我还想获得用户评级的项目列表以及评级值:
user.ratings.forEach(function(rating){
<%= user.username %> has rated <%= rating.item.name %> and gave it a <%= rating.value %>
});
我的“评分”架构应该是什么样的?是否可以存储两个值?用户对象ID和评级值(整数)并具有这些的集合?
我用我的方法看到的另一个问题是mongoose还不支持深度填充,所以我必须使用一个模块(https://github.com/JoshuaGross/mongoose-subpopulate),很大程度上是未测试或以不同的方式存储它,不会有多个嵌套级别,所以我可以用.populate()
获取我的数据感谢任何反馈,因为我是noSQL的新手,也许我对此过于复杂。
答案 0 :(得分:6)
我会像你说的那样做。我会使用评级架构:
var RatingSchema = new Schema({
, _user : { type: ObjectId, ref: 'User' }
, _item : { type: ObjectId, ref: 'Item' }
, value : Integer
});
如果您希望能够从User架构访问评级,则必须添加一个钩子,以便将任何已保存的RatingSchema添加到user.ratings。
var UserSchema = new Schema({
/* ... */
ratings: [{ type: Schema.ObjectId, ref: 'Rating'}]
});
RatingSchema.post('save', function () {
// push this.id to this._user.ratings
// save this._user
});
关于“我用我的方法看到的另一个问题是mongoose还不支持深度填充”,如果你不想使用mongoose-subpopulate hack,我建议你重构你的模型加载到静态方法。例如:
UserSchema.statics.findByIdAndDeepPopulate = function (i, cb) {
UserSchema.findOne(id)
.exec(function(err, user) {
if (err || !user) return cb(new Error('User not found'));
if (user._ratings.length == 0) return cb(null, user);
// Load and populate every ratings in user._ratings
for(var i = 0; i < user._ratings.length; i++) {
function(i) {
RatingSchema
.populate('_item')
.exec(err, function(rating) {
user._ratings[i] = rating;
if (i == user._ratings.length) return cb(null, user);
});
}(i);
}
});
}
编辑:现在我再考虑一下,为什么不简单地将评级存储为UserSchema中的嵌入文档?
var UserSchema = new Schema({
/* ... */
ratings: [ RatingSchema ]
});
然后你可以这样填充:
UserSchema.findOne(id)
.populate('ratings._item')
.exec(function(err, user) {
if (err || !user) return next(new Error('User not found'));
console.log(user.ratings);
});
答案 1 :(得分:3)
您希望避免双重交叉链接,因为这意味着维护的次数是原来的两倍,并且由于Mongo不支持事务,因此当您预期双重连接时,它会创建半连接数据的可能性。话虽这么说,我重新考虑你的模式:
var like = {
itemid: { type: Schema.ObjectId, ref: 'Item'}
, rating: Number
};
var UserSchema = new Schema({
username : { type: String, required: true, index: { unique: true }
, likes : [like]
, dislikes : [like]
});
UserSchema.index({ 'likes.itemid': 1 });
UserSchema.index({ 'dislikes.itemid': 1 });
var User = db.model('User', UserSchema);
var ItemSchema = new Schema({
name: String
});
var Item = db.model('Item', ItemSchema);
您可以通过以下方式添加喜欢或不喜欢的内容:
var piano = new Item({name: 'Mason & Hamlin Baby Grand Piano' });
var Joe = new User({ username: 'Joe_Smith' });
Joe.likes.push({ itemid: piano._id, rating: 10 });
当你想查找项目的喜欢时:
User.find({ 'likes.itemid': piano._id }, function(err, userLikes) {
...
});
如果对你没有任何感觉,那么你可以创建第三个集合......
var UserSchema = new Schema({
username : { type: String, required: true, index: { unique: true }
});
var User = db.model('User', UserSchema);
var ItemSchema = new Schema({
name: String
});
var Item = db.model('Item', ItemSchema);
var LikesSchema = new Schema({
, userid: { type: Schema.ObjectId, ref: 'User'}
, itemid: { type: Schema.ObjectId, ref: 'Item'}
, rating: Number
});
LikesSchema.index({ userid: 1, itemid: 1 }, { unique: true });
在这种情况下,最简单的做法是正面评级是一个类似而负面评级是不喜欢的。