如何在for循环中更新MongoDb文档

b91juud3  于 2023-11-17  发布在  Go
关注(0)|答案(5)|浏览(208)

我有一个对象数组

df =[{user: "name1", newdata: "data1"},
     {user: "name2", newdata: "data3"},
     ....
]

字符串
我有一个包含userkey1字段的集合。我想找到用户并使用dato.newdata更新'key1'。我试图包含在for循环中,但它不起作用。这是我的代码:

const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';

client.connect(function(error){
    for (dato of df){
        client.db(dbasename).collection(collectionname).updateOne(
            {user: dato.user},
            {$set: {key1: dato.newdata}},
            function(error,result){
                if (error) console.log(error);
                if (result) {
                    console.log(JSON.stringify(result));
                }
            }
        );  
    }
})


附加信息:我注意到它对第一个找到的用户有效。也许updateOne返回了一个promise,而我没有正确管理它?
我已经尝试了其他的代码,正如你们中的一些人所建议的那样。但是它不起作用。:

const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';

async function changeValue (dbasename,collectionname, user, newData) {
  client.db(dbasename).collection(collectionname).updateOne(
      {user: user},
      {$set: {key1: newdata}},
      {upsert:false},
      {multi:false},
      function(error,result){
        if (error) console.log(error);
        if (result) {
            console.log(JSON.stringify(result));
        }
    }
  );
}

client.connect(function(error){
  for (dato of df){
     await changeValue(dbasename,collectionname, dato.user, dato.newdata);
  }
})


编译器说:SyntaxError: await is only valid in async function

z6psavjg

z6psavjg1#

最后,这段代码是有效的。

async function changeValue(dbasename, collectionname, dato){
        let client = await MongoClient.connect(url).catch(error => {console.log(error)});
        if (!client) {return;};
        let db = client.db(dbasename);
        let collection = db.collection(collectionname);
        collection.updateOne(
            {user: dato.user},
            {$set: {key1: dato.newdata}},
            function(error,result){
                    if (error) console.log(error);
                    if (result.result.n === 0) {
                            console.log(dato.user); //print not found users
                    }
            }
        );
        await client.close();
    };  

    for (dato of df){
        changeValue(dbasename, collectionname, dato);
    }

字符串

nbewdwxp

nbewdwxp2#

如果你在updateOne中使用await,那么它就可以工作了,例如我使用以下循环在Node.js中遍历http请求的主体并更新我的集合中的文档:

// req.body looks like this { firstname: 'Jack', age: '34', ... }
// db collection looks like this:
// { name: "firstname", value" "Tom" }
// { name: "age", value" "23" }

async (req, res) => {
    await client.connect();
    const database = client.db('test');
    const profile = database.collection('profile');

    for (const property in req.body) {
      const query = { name: property };
      const updateDoc = {
        $set: { value: req.body[property] }
      };
      await profile.updateOne(query, updateDoc);
    }

    const data = await profile.find().toArray();
    res.json(data);
}

字符串

u7up0aaq

u7up0aaq3#

有两种方法可以做到这一点:

确实使用了for循环。

在这里,它是关于浏览你的循环,并为每个元素,执行和更新操作。

const collection = client.db(dbasename).collection(collectionname);
const promises = df.map(x => {
    return new Promise(function(resolve, reject){
        collection.updateOne({
            user : x.user
        },
        {$set: {key1: x.newdata}},
        function(err, result){
            if(err) reject(err)
            else resolve(result)
        })
    })
});
await Promise.all(promises);

字符串

使用聚合管道。

for..循环方法有一个主要的缺点,你将执行尽可能多的操作,因为你有你的数组中的元素。这对小数组是好的,但考虑到更新甚至200个元素,它开始发臭。替代方案是使用聚合框架更新1一次去所有元素。
首先保存你的df数组到一个新的集合中,我们称之为temp_update_data

// using the promise API, we save df into a new collection, we also rename the newdata field into key1
await client.db(dbasename).collection("temp_update_data").insertMany(df.map(x => ({user : x.user, key1: x.newData})));


现在,您在temp_update_data中有了将用户与键1关联的数据,您可以使用合并操作,通过匹配user字段,将newData添加到collectionname的对象中

const pl = [
    {
         $merge: {
             into: "collectionname",
             on: "user",
             whenMatched: "merge",
             whenNotMatched: "discard",
        }
    }
];
await client.db(dbasename).collection("temp_update_data").aggregate(pl);

// remove temp data
await client.db(dbasename).collection("temp_update_data").deleteMany({});


这只需要3次对数据库的调用(保存数据,合并,删除临时数据),并利用MongoDB算法的优化,随着要更新的对象数量的增加而节省时间。

jgovgodb

jgovgodb4#

MongoDB调用是循环的,但到目前为止,循环完成了所有迭代,并没有等待操作结束。
我觉得你可以做这样的事,

async changeValue(user, newData) {
    client.db(dbasename).collection(collectionname).updateOne(
        {user: user},
        {$set: {key1: newdata}},
        function(error,result){
            if (error) console.log(error);
            if (result) {
                console.log(JSON.stringify(result));
            }
        }
    );
}

for (dato of df){
    await changeValue(dato.user, dato.newdata);
}

字符串
这只是一个粗略的想法,你可能需要做一些修改。但我认为这可能有助于理解需要做什么。

niknxzdl

niknxzdl5#

由于MongoDB操作是循环的,for循环不会在迭代过程中等待插入/更新文档等操作。
所以,你必须使用forEach和await来确保文档在下一次迭代之前得到更新。

async changeValue(user, newData) {
        db.collectionName.updateOne(
            {user: user},
            {$set: {key1: newdata}},
            {upsert:false},
            {multi:false}
        );
    }
      df.forEach(function(item){
       await changeValue(item.user,item.newData);
    });

字符串

相关问题