В MongoDB, если у меня есть структура документа следующим образом:
{ "_id" : { "$binary" : "jchPoPd7PUS1w+sR7is23w==", "$type" : "03" },
"companies" :
[
{ "_id" : { "$binary" : "jchPoPd7PUS1w+sR7is23w==", "$type" : "03" },
"name" : "Google" },
{ "_id" : { "$binary" : "jchPoPd7PUS1w+sR7is23w==", "$type" : "03" },
"name" : "Greenfin" },
{ "_id" : { "$binary" : "jchPoPd7PUS1w+sR7is23w==", "$type" : "03" },
"name" : "Zynet" }
],
"firstname" : "Peter",
"surname" : "Smith" }
(т.е. документ Person
с массивом Companies
, встроенным в документ человека), то как мне обновить ВСЕ вхождения определенной компании (цель через компанию _id) с помощью одного запроса + обновление?
Я пробовал следующее:
MongoCollection personCollection = mdb.GetCollection("person");
BsonBinaryData bin = new BsonBinaryData(new Guid("0AE91D6B-A8FA-4D0D-A94A-91D6AC9EE343"));
QueryComplete query = Query.EQ("companies._id", bin);
var update = Update.Set("companies.name", "GreenfinNewName");
SafeModeResult result = personCollection.Update(query, update, UpdateFlags.Multi);
но это не сработает. Думаю, мой вопрос сводится к двум вопросам: как настроить таргетинг на встроенные компании в исходный запрос, а затем как установить новое название компании в инструкции Set. Примечание. В этом примере я решил "денормализовать" данные компании и вставить ее в документ каждого человека, поэтому может быть несколько документов с одинаковым идентификатором и именем компании. Большое спасибо.
UPDATE: Используя технику Bugai13, я стал ближе. Это работает:
MongoCollection personCollection = mdb.GetCollection("person");
QueryComplete query = Query.EQ("companies.name", "Bluefin");
var update = Update.Set("companies.$.companynotes", "companynotes update via name worked");
SafeModeResult result = personCollection.Update(query, update, UpdateFlags.Multi, SafeMode.True);
Но это не работает:
MongoCollection personCollection = mdb.GetCollection("person");
BsonBinaryData bin = new BsonBinaryData(new Guid("0AE91D6B-A8FA-4D0D-A94A-91D6AC9EE343"));
Builders.QueryComplete query = Query.EQ("companies._id", bin);
var update = Update.Set("companies.$.companynotes", "companynotes update via id worked");
SafeModeResult result = personCollection.Update(query, update, UpdateFlags.Multi, SafeMode.True);
Итак, я пока не могу обновить с использованием первичного ключа, что мне нужно сделать...
Полагаю, вы должны взглянуть на оператор позиционирования в mongodb:
var update = MongoDB.Driver.Builders.Update
.Set("companies.$.name", "GreenfinNewName");
^^
all magic here
Примечание: выше код обновит только first
согласованный элемент в массиве. Поэтому, если у вас есть две компании в вложенном массиве с name = GreenfinNewName
выше, код будет обновляться только с первого раза.
Примечание: UpdateFlags.Multi
означает несколько документов, но не несколько элементов в вложенном массиве.
Update:
QueryComplete query = Query.EQ("companies._id",
BsonValue.Create(new Guid("0AE91D6B-A8FA-4D0D-A94A-91D6AC9EE343")));
var update = Update.Set("companies.$.companynotes", "companynotes");
personCollection.Update(query, update, UpdateFlags.Multi, SafeMode.True);
Надеюсь на эту помощь!
Просто хотел сказать спасибо вам обоим. Изучение Mongo и этой нити помогло.
Я использую драйвер 10gen С#, и для справки это мой код:
MongoServer mongo = MongoServer.Create();
MongoDatabase db = mongo.GetDatabase("test");
MongoCollection<BsonDocument> coll = db["contacts"];
BsonDocument doc = new BsonDocument();
doc["FirstName"] = "Daniel";
doc["LastName"] = "Smith";
doc["Address"] = "999 Letsby Avenue";
doc["City"] = "London";
doc["County"] = "Greater London";
doc["Postcode"] = "N13";
coll.Insert<BsonDocument>(doc);
QueryComplete qSel = Query.EQ("Postcode", "N13");
MongoCursor<BsonDocument> cur = coll.Find(qSel);
foreach (BsonDocument bdoc in cur)
{
Console.WriteLine(bdoc["FirstName"] + ":" + bdoc["Address"]);
}
UpdateBuilder docTwo = Update.Set("Postcode", "MK10");
coll.Update(qSel, docTwo, UpdateFlags.Multi);
QueryDocument qSel2 = new QueryDocument("FirstName", "Daniel");
MongoCursor<BsonDocument> cur2 = coll.Find(qSel2);
foreach (BsonDocument bsdoc in cur2)
{
Console.WriteLine(bsdoc["FirstName"] + " : " + bsdoc["Postcode"]);
}