简体   繁体   English

将对象推入对象数组

[英]Push objects into object array

The problem: 问题:

I want to keep track of my uploaded files by writing the fileinformation each uploaded file for a multi upload into my database. 我想通过将每个上传文件的文件信息写入文件信息来跟踪上传的文件,以将其多次上传到我的数据库中。 However when I upload 2 files it usually creates 3 entries in the database and when I upload 6 files it will create a lot more than 6 entries. 但是,当我上传2个文件时,通常会在数据库中创建3个条目,而当我上传6个文件时,它将创建远远超过6个条目。

My db function: 我的数据库功能:

function saveAssetInDatabase(project, fileInformation) {
    return new Promise((reject, resolve) => {
        let uploaded_file = {}
        uploaded_file = fileInformation
        uploaded_file.file_type = 'asset'
        uploaded_file.display_name = fileInformation.originalname
        project.uploaded_files.push(uploaded_file)
        project.save()
    })
}

The simplified code which calls the function: 调用该函数的简化代码:

for(var i=0; i<req.files["sourceStrings"].length; i++) {
    // Unknown file format, let's save it as asset
    saveAssetInDatabase(project, fileInformation).then(result => {
        return res.status(200).send()
    }).catch(err => {
        logger.error(err)
        return res.status(500).send()
    })
}

I guess that there is something wrong with my db function as it leads to duplicate file entries. 我猜我的db函数有问题,因为它导致重复的文件条目。 What am I doing wrong here? 我在这里做错了什么? One file should get one entry. 一个文件应获得一个条目。

Problem 问题

Each time in your for loop create a promise then send your that time project object. 每次在for循环中创建一个Promise,然后发送该时间项目对象。 It's not correct way. 这不是正确的方法。 Each promise resolved you have send project object to DB then store it. 每个已解决的承诺都已将项目对象发送到DB,然后将其存储。

For example you have 3 asset details. 例如,您有3个资产详细信息。 While first time loop running first asset data would store in project object and the promise resolved you have send that time project in your DB store it. 当运行第一次资产的第一次循环将存储在项目对象中并且已解决诺言时,您已经将该时间项目发送到了数据库中。 This time project object has first asset details. 这次项目对象具有第一个资产详细信息。

While second time loop running second asset data would store in project object with first asset data and the promise resolved you have send that time project in your DB store it. 当运行第二个时间循环的第二个资产数据将与第一个资产数据一起存储在项目对象中,并且已解决的承诺已将那个时间项目发送到数据库中并将其存储。 This time project object has first and second asset details. 这次项目对象具有第一和第二资产详细信息。

While third time loop running third asset data would store in project object with first and second asset data and the promise resolved you have send that time project in your DB store it. 运行第三次资产循环的第三次时间循环会将第一个和第二个资产数据存储在项目对象中,并且已解决的承诺已将那个时间项目发送到数据库中并将其存储。 This time project object has first, second and third asset details. 这次项目对象具有第一,第二和第三资产详细信息。

So you have store same datas in your DB. 因此,您已经在数据库中存储了相同的数据。

Solution

You have use Promise.all. 您已经使用Promise.all。 Resolve all assest's promise after you store your project data in your DB. 将项目数据存储在数据库中后,请兑现所有承诺。

    // your DB function
    function saveAssetInDatabase(project, fileInformation) {
        return new Promise((resolve, reject) => {
            let uploaded_file = {}
            uploaded_file = fileInformation
            uploaded_file.file_type = 'asset'
            uploaded_file.display_name = fileInformation.originalname
            project.uploaded_files.push(uploaded_file)
            project.save();
            resolve();
        })
    }

    // calls function

    let promiseArray = [];
    for(var i=0; i<req.files["sourceStrings"].length; i++) {
        promiseArray.push(saveAssetInDatabase(project, fileInformation));
    }

    Promise.all(promiseArray).then(result => {
        return res.status(200).send();
    }).catch(err => {
        logger.error(err)
        return res.status(500).send()
    })
}

If I read the specs on model.save correctly on the mongoose website, the problem with your save is rather that you are always reusing the original project, and not the newly saved project that should contain the latest state. 如果我在猫鼬网站上正确阅读了有关model.save的规格,则保存的问题在于您总是在重用原始项目,而不是重新使用应该包含最新状态的新保存的项目。

So what you are essentially are doing: 因此,您实际上在做什么:

project.files.push(file1);
// file1 is marked as new
project.save();
project.files.push(file2);
// file1 & file2 are marked as new 
// (the project doesn't know file1 has been saved already)
// ...

Now, that actually brings quite some advantages, since you are doing currently a save per file, while you could save all files at once ;) 现在,这实际上带来了很多好处,因为您当前正在按文件保存,而您可以一次保存所有文件;)

I guess the easiest way would be to put the project.save method outside of your for loop and change your first method like 我猜最简单的方法是将project.save方法放在for循环之外,然后更改第一个方法,例如

function saveAssetInDatabase(project, fileInformation) {
    let uploaded_file = {};
    uploaded_file = fileInformation;
    uploaded_file.file_type = 'asset';
    uploaded_file.display_name = fileInformation.originalname;
    project.uploaded_files.push(uploaded_file);
}

with the for loop changed to 将for循环更改为

function saveSourceString(project, req) {
    for(var i=0; i<req.files["sourceStrings"].length; i++) {
        // Unknown file format, let's save it as asset
        saveAssetInDatabase(project, fileInformation);
    }
    // save after all files were added
    return project.save().then(result => {
        return res.status(200).send()
      }).catch(err => {
        logger.error(err)
        return res.status(500).send()
      });
}

Note that project.save() will return a promise, with an argument containing the newly saved project . 注意project.save()将返回一个promise,其参数包含新保存的project If you wish to manipulate this object at a later time, make sure you take the saved file, and not, as you have done till now, the non-saved model 如果您希望以后再操作该对象,请确保获取已保存的文件,而不要像现在一样处理未保存的模型

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM