2016-04-01 4 views
0

Вот схема, над которой я работаю.Обновление ссылки наряду с другими значениями Mongoose

var testSchema = mongoose.Schema({ 
    userCreated : { 
     type : mongoose.Schema.Types.ObjectId, 
     ref : "User" 
    }, 
    points : {type: Number, default: 0}, 
    numVotes : {type: Number, default: 0}, 
    createdAt : Date, 
    updatedAt : Date, 
}, { timestamps : true }); 

Теперь я пытаюсь написать функцию, которая будет увеличиваться два поля по этому документу (points и numVotes, а также дополнительное points поля, которое существует на схеме пользователя.

Вот мой попытка.

testSchema.statics.incrementTest = function(id, ...) { 
    this.findByIdAndUpdate(id, {$inc : { 
     points : 5, 
     numVotes : 1, 
     'userCreated.points' : 5 
    }}).exec(); 
} 

Теперь этот код, который я написал не работает. Однако, когда я закомментируйте 'userCreated.points' : 5 линии, остальные два поля делать инкремент, как и ожидалось. Мои вопрос в том, как наилучшим образом использовать мангуст для одновременного обновления полей в документе и полей в поддоку?

+0

Mongoose 'ref' типы не на самом деле хранятся в виде документов, сохраняется только идентификатор объекта. Таким образом, путь 'userCreated.points' не существует в testSchema, поэтому не может быть обновлен. Вам нужно будет выполнить другой запрос обновления для обновления документа пользователя. –

ответ

1

Данные здесь содержатся в разных коллекциях, поэтому ни один оператор обновления не может увеличивать счетчики одновременно.

Для того, чтобы получить согласованное представление, вам понадобится «связать» ваши заявления об обновлении и использовать результаты возврата каждого для построения ответа.

В зависимости от ваших потребностей вы можете использовать Promise с этим:

testSchema.statics.incrementTest = function(id) { 
    var self = this; 
    return new Promise(function(resolve,reject) { 
    self.findByIdAndUpdate(
     id, 
     { 
     "$inc": { 
      "points": 5, 
      "numVotes": 1 
     } 
     }, 
     { "new": true } 
    ).then(function(test) { 
     var userModel = test.schema.path("userCreated").options.ref; 
     mongoose.model(userModel).findByIdAndUpdate(
     test.userCreated, 
     { "$inc": { "points": 5 } }, 
     { "new": true } 
    ).then(function(user) { 
     test.userCreated = user; 
     resolve(test); 
     }) 
    }).catch(reject) 
    }) 
}; 

Что вы можете ссылаться на модели:

Test.incrementTest("56fe279d363ce91765d9e39e").then(function(test) { 
    console.log(JSON.stringify(test,undefined,2)); 
}).catch(function(err) { 
    throw err; 
}) 

Или вы можете использовать async.waterfall из async библиотеки, если что подходит вам лучше:

testSchema.statics.incrementTest = function(id,callback) { 
    var self = this; 

    async.waterfall(
    [ 
     function(callback) { 
     self.findByIdAndUpdate(
      id, 
      { 
      "$inc": { 
       "points": 5, 
       "numVotes": 1 
      } 
      }, 
      { "new": true }, 
      callback 
     ) 
     }, 
     function(err,test) { 
     if (err) callback(err); 
     var userModel = test.schema.path("userCreated").options.ref; 
     mongoose.model(userModel).findByIdAndUpdate(
      test.userCreated, 
      { "$inc": { "points": 5 } }, 
      { "new": true }, 
      function(err,user) { 
      if (typeof(user) !== "undefined") 
       test.userCreated = user; 
      callback(err,test); 
      } 
     ); 
     } 
    ], 
    callback 
); 
}; 

Который имеет сходное использование:

Test.incrementTest("56fe279d363ce91765d9e39e",function(err,test) { 
    if (err) throw err; 
    console.log(JSON.stringify(test,undefined,2)); 
}) 

Оба должны давать вам результат обратно, который показывает измененные данные в обеих объектах для обоего коллекций:

{ points: 5, 
    numVotes: 1, 
    __v: 0, 
    userCreated: { points: 5, __v: 0, _id: 56ff1aa6dba6d13e798fc894 }, 
    createdAt: Sat Apr 02 2016 12:04:38 GMT+1100 (AEDT), 
    updatedAt: Sat Apr 02 2016 12:04:38 GMT+1100 (AEDT), 
    _id: 56fe279d363ce91765d9e39e }