MongoDB - Mongoose - TypeError: сохранение не является функцией - PullRequest
0 голосов
/ 16 сентября 2018

Я пытаюсь выполнить обновление документа MongoDB (используя mongoose), сначала используя .findById для получения документа, а затем обновляя поля в этом документе новыми значениями. Я все еще немного новичок в этом, поэтому я использовал учебник, чтобы понять, как заставить его работать, затем я обновлял свой код для своих нужд. Вот учебник: MEAN App Учебник с Angular 4 . В исходном коде была определена схема, но мое требование - общий интерфейс MongoDB, который будет просто принимать любую полезную нагрузку, отправляемую ему, и отправлять ее в MongoDB. Оригинальный урок имел что-то вроде этого:

exports.updateTodo = async function(todo){
    var id = todo.id

    try{
        //Find the old Todo Object by the Id

        var oldTodo = await ToDo.findById(id);
    }catch(e){
        throw Error("Error occured while Finding the Todo")
    }

    // If no old Todo Object exists return false
    if(!oldTodo){
        return false;
    }

    console.log(oldTodo)

    //Edit the Todo Object
    oldTodo.title = todo.title
    oldTodo.description = todo.description
    oldTodo.status = todo.status


    console.log(oldTodo)

    try{
        var savedTodo = await oldTodo.save()
        return savedTodo;
    }catch(e){
        throw Error("And Error occured while updating the Todo");
    }
}

Однако, поскольку я не хочу схемы и хочу что-либо пропустить, я не хочу присваивать статические значения конкретным именам полей, таким как заголовок, описание, статус и т. Д. Итак, я придумал это :

exports.updateData = async function(update){
    var id = update.id

    // Check the existence of the query parameters, If they don't exist then assign a default value
    var dbName = update.dbName ? update.dbName : 'test'
    var collection = update.collection ? update.collection : 'testing'; 

    const Test = mongoose.model(dbName, TestSchema, collection);

    try{
        //Find the existing Test object by the Id
        var existingData = await Test.findById(id);
    }catch(e){
        throw Error("Error occurred while finding the Test document - " + e)
    }

    // If no existing Test object exists return false
    if(!existingData){
        return false;
    }

    console.log("Existing document is " + existingData)

    //Edit the Test object
    existingData = JSON.parse(JSON.stringify(update))

    //This was another way to overwrite existing field values, but
    //performs a "shallow copy" so it's not desireable
    //existingData = Object.assign({}, existingData, update)

    //existingData.title = update.title
    //existingData.description = update.description
    //existingData.status = update.status

    console.log("New data is " + existingData)

    try{
        var savedOutput = await existingData.save()
        return savedOutput;
    }catch(e){
        throw Error("An error occurred while updating the Test document - " + e);
    }
}

Моя первоначальная проблема заключалась в том, что у меня было много проблем с получением новых значений для замены старых. Теперь, когда это было решено, я получаю сообщение об ошибке «TypeError :istingData.save не является функцией». Я думаю, что тип данных изменился или что-то, и теперь это не принимается. Когда я раскомментирую статические значения, которые были в старом учебном коде, это работает. Это также поддерживается регистрацией в моей консоли до и после того, как я присоединяюсь к объектам, потому что первый печатает фактические данные, а второй печатает [объект Object]. Тем не менее, я не могу понять, чего он ожидает. Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ: Я понял это. Очевидно, у Mongoose есть собственный тип данных «Модель», который изменяется, если вы делаете что-то безумное с базовыми данными, используя такие вещи, как JSON.stringify. Я использовал Object.prototype.constructor, чтобы выяснить фактический тип объекта следующим образом:

console.log("THIS IS BEFORE: " + existingData.constructor);
existingData = JSON.parse(JSON.stringify(update));
console.log("THIS IS AFTER: " + existingData.constructor);

И я получил это:

THIS IS BEFORE: function model(doc, fields, skipId) {
  model.hooks.execPreSync('createModel', doc);
  if (!(this instanceof model)) {
    return new model(doc, fields, skipId);
  }
  Model.call(this, doc, fields, skipId);
}
THIS IS AFTER: function Object() { [native code] }

Который показал мне, что на самом деле происходит. Я добавил это, чтобы исправить это:

existingData = new Test(JSON.parse(JSON.stringify(update)));

В соответствующей заметке мне, вероятно, следует просто использовать собственный драйвер MongoDB на данный момент, но он работает, поэтому я просто покажу его в своем списке дел.

1 Ответ

0 голосов
/ 17 сентября 2018

Теперь вы нашли решение, но я бы предложил использовать драйвер MongoDB, который бы заставил ваш код выглядеть примерно так и исключил бы изначальную проблему:

// MongoDB Settings
const MongoClient = require(`mongodb`).MongoClient;
const mongodb_uri = `mongodb+srv://${REPLACE_mongodb_username}:${REPLACE_mongodb_password}@url-here.gcp.mongodb.net/test`;
const db_name = `test`;
let db; // allows us to reuse the database connection once it is opened

// Open MongoDB Connection
const open_database_connection = async () => {
  try {
    client = await MongoClient.connect(mongodb_uri);
  } catch (err) { throw new Error(err); }
  db = client.db(db_name);
};


exports.updateData = async update => {

  // open database connection if it isn't already open
  try {
    if (!db) await open_database_connection();
  } catch (err) { throw new Error(err); }


  // update document
  let savedOutput;
  try {
    savedOutput = await db.collection(`testing`).updateOne( // .save() is being depreciated
      { // filter
        _id: update.id // the '_id' might need to be 'id' depending on how you have set your collection up, usually it is '_id'
      },
      $set: { // I've assumed that you are overwriting the fields you are updating hence the '$set' operator
        update // update here - this is assuming that the update object only contains fields that should be updated
      }

      // If you want to add a new document if the id isn't  found add the below line
      // ,{ upsert: true }

    );
  } catch (err) { throw new Error(`An error occurred while updating the Test document - ${err}`); }


  if (savedOutput.matchedCount !== 1) return false; // if you add in '{ upsert: true }' above, then remove this line as it will create a new document

  return savedOutput;
}

Коллекция testing должна быть создана перед этим кодом, но это только одноразовая вещь, которая очень проста - если вы используете MongoDB Atlas, то вы можете использовать MongoDB Compass / go в своем онлайн-администраторе для создания коллекция без единой строки кода ...

Насколько я понимаю, вам нужно дублировать объект update. Вышеизложенное сокращает количество обращений к базе данных с 2 до одного и позволяет повторно использовать соединение с базой данных, возможно, где-либо еще в приложении, что поможет ускорить процесс. Также не храните свои учетные данные MongoDB непосредственно в коде.

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