Модель mongoose не имеет доступа к проводимым соединениям - PullRequest
0 голосов
/ 19 февраля 2019

В моем текущем экспресс-приложении я хочу использовать новую возможность многодокументных транзакций mongodb.

Прежде всего важно указать, как я подключаюсь и работаю с моделями

Мой app.js (сервер) сначала подключается к БД с помощью db.connect ().

Мне нужны все модели в моем файле db.index.Поскольку модели будут инициированы с использованием одной и той же ссылки мангуста, я предполагаю, что будущие потребности моделей на разных маршрутах указывают на подключенное и одно и то же соединение.Пожалуйста, исправьте меня, если я ошибаюсь с любым из этих предположений.

Я сохраняю ссылку на соединение внутри объекта состояния и возвращаю ее при необходимости позже для моей транзакции

. / Db/index.ts

const fs       = require('fs');
const path     = require('path');
const mongoose = require('mongoose');

const state = {
 connection = null,
}

// require all models
const modelFiles = fs.readdirSync(path.join(__dirname, 'models'));
modelFiles
.filter(fn => fn.endsWith('.js') && fn !== 'index.js')
.forEach(fn => require(path.join(__dirname, 'models', fn)));

const connect = async () => {
  state.connection = await mongoose.connect(.....);
  return;
}

const get = () => state.connection; 

module.exports = {
 connect,
 get,
}

файлы моей модели содержат мои необходимые схемы

. / db / models / example.model.ts

const mongoose   = require('mongoose');
const Schema     = mongoose.Schema;
const ExampleSchema = new Schema({...);

const ExampleModel = mongoose.model('Example', ExampleSchema);
module.exports  = ExampleModel;

Теперь маршрут, по которому я пытаюсь выполнить основную транзакцию.F

. / Routs / item.route.ts

const ExampleModel = require('../db/models/example.model');

router.post('/changeQty', async (req,res,next) => {

  const connection = db.get().connection;
  const session = await connection.startSession(); // works fine

  // start a transaction
  session.startTransaction(); // also fine

  const {someData} = req.body.data;

  try{

     // jsut looping that data and preparing the promises
     let promiseArr = [];
     someData.forEach(data => {
        // !!! THIS TRHOWS ERROR !!!
        let p = ExampleModel.findOneAndUpdate(
          {_id : data.id},
          {$incr : {qty : data.qty}},
          {new : true, runValidators : true}
        ).session(session).exec();
        promiseArr.push(p);
     })        

     // running the promises parallel
     await Promise.all(promiseArr);

     await session.commitTransaction();

    return res.status(..)....;

  }catch(err){
     await session.abortTransaction();
    // MongoError : Given transaction number 1 does not match any in-progress transactions.
    return res.status(500).json({err : err}); 
  }finally{
    session.endSession();
  }

})

Но я всегда получаю следующую ошибку, которая, вероятно, связана со ссылкой на соединениемои модели.Я предполагаю, что они не имеют доступа к соединению, которое запустило сеанс, поэтому они не знают о сеансе.

MongoError: Данная транзакция номер 1 не соответствует ни одной из выполняемых транзакций.

Может быть, мне как-то нужно инициировать модели внутри db.connect с помощью ссылки на прямое соединение?

Где-то есть большая ошибка, и я надеюсь, что вы можете привести меня к правильномудорожка.Я ценю любую помощь, заранее спасибо

1 Ответ

0 голосов
/ 28 февраля 2019

Это потому, что вы выполняете операции параллельно:

Итак, у вас есть куча условий гонки.Просто используйте async / await

и сделайте вашу жизнь проще.

let p = await ExampleModel.findOneAndUpdate(
              {_id : data.id},
              {$incr : {qty : data.qty}},
              {new : true, runValidators : true}
            ).session(session).exec();

Ссылка: https://github.com/Automattic/mongoose/issues/7311

Если это не сработает, попробуйтевыполнять обещания одно за другим, а не promise.all () .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...