#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 } } ]
в обновленной записи отсутствует информация о временной метке, но я уверен, что вы справитесь с этим.