пользовательское обновление нескольких документов в mongoose, соответствующих заданным идентификаторам

#mongodb #mongoose

#mongodb #mongoose

Вопрос:

У меня есть схема, подобная этой

  var betDataSchema = new mongoose.Schema(
 { 
  name: { type: String, required: true },
  value: { type: Object, required: true },
  _id : {type: String, required: true}
 },
 { timestamps: true, _id: false }
 );
  

Я хочу обновить поле значения во всем документе определенным образом

запросите весь документ сразу по _id и обновите соответствующий _id соответствующим документом _id, предоставленным, если соответствующий документ _id не существует, чем создайте новый

я попытался написать код

     BetDataModel.updateMany({
         // filters
      name: 'listEventTypes',
      _id: { $in: newarr.map(x => x._id) }
    },

     // new documents to be updated on the existing document
    [doc1, doc2, doc3],

    // if not present create a new one
     {upsert: true, new: true}
    )
  })
  

Ответ №1:

Попытался воссоздать минимальную среду, вот сценарий, который я придумал:

 const mongoose = require("mongoose");
const shortid = require("shortid");

mongoose.connect("mongodb://localhost/test9999", {
    useNewUrlParser: true
});
const db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error:"));
db.once("open", async function() {
    await mongoose.connection.db.dropDatabase();

    var betDataSchema = new mongoose.Schema({
        name: {
            type: String,
            required: true
        },
        value: {
            type: Object,
            required: true
        },
        _id: {
            type: String,
            required: true
        }
    }, {
        timestamps: true,
        _id: false
    });

    const BetDataModel = mongoose.model("BetDataModel", betDataSchema);

    const b1 = new BetDataModel({
        name: "Pop",
        value: {
            x: 5
        },
        _id: "ID1"
    });
    const b2 = new BetDataModel({
        name: "Rock",
        value: {
            x: 5
        },
        _id: "ID2"
    });
    const b3 = new BetDataModel({
        name: "Rock22",
        value: {
            x: 5
        },
        _id: "ID3"
    });

    await b1.save();
    await b2.save();
    await b3.save();

    newarr = [new BetDataModel({
        _id: 'ID2',
        value: {
            x: 10
        },
        name: "Newid2"
    }), new BetDataModel({
        _id: 'ID4',
        value: {
            x: 11
        },
        name: "Newid44"
    })];

    bulk = BetDataModel.collection.initializeOrderedBulkOp();
    for (i in newarr) {
        var doc = newarr[i];
        bulk.find({
            _id: doc._id /* additional filters here */
        }).upsert().update({
            $set: {
                name: doc.name,
                value: doc.value
            }
        }, {
            multi: true
        });
    }
    await bulk.execute();


    await BetDataModel.find(function(err, bets) {
        if (err) return console.error(err);
        console.log(bets);
    });
});
  

updateMany Идея — это правильное направление, но, насколько я понимаю, вы должны указать литерал при подготовке updateMany запроса. В вашем случае вы хотите динамически выполнить итерацию по списку и подготовить bulk запрос. Итак, я полагаю, что в моем примере это будет переведено в несколько операторов ОБНОВЛЕНИЯ, но будет выполнено в одном запросе.

Эта часть наиболее актуальна:

 bulk = BetDataModel.collection.initializeOrderedBulkOp();
for (i in newarr) {
    var doc = newarr[i];
    bulk.find({
        _id: doc._id /* additional filters here */
    }).upsert().update({
        $set: {
            name: doc.name,
            value: doc.value
        }
    }, {
        multi: true
    });
}
await bulk.execute(); 
  

В моем случае этот код выдает следующее:

 [ { _id: 'ID1',
    name: 'Pop',
    value: { x: 5 },
    createdAt: 2020-08-25T08:58:59.335Z,
    updatedAt: 2020-08-25T08:58:59.335Z,
    __v: 0 },
  { _id: 'ID2',
    name: 'Newid2',
    value: { x: 10 },
    createdAt: 2020-08-25T08:58:59.359Z,
    updatedAt: 2020-08-25T08:58:59.359Z,
    __v: 0 },
  { _id: 'ID3',
    name: 'Rock22',
    value: { x: 5 },
    createdAt: 2020-08-25T08:58:59.361Z,
    updatedAt: 2020-08-25T08:58:59.361Z,
    __v: 0 },
  { _id: 'ID4', name: 'Newid44', value: { x: 11 } } ]
  

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