问题
My collections contain nested document and I'm trying to get "Text" present in any of the nested fields such as:
var rerun = { $or: [
{"code_exception.java_40.code.Text": { $exists : true, $ne : "" } },//13816
{"code_exception.java_15.code.Text":{ $exists : true, $ne : ""} },//13485
{"code_exception.java_10.code.Text":{ $exists : true, $ne : ""} },//12994
{"code_exception.java_2.code.Text": { $exists : true, $ne : ""} },//13294
{"code_exception.java_4.code.Text": { $exists : true, $ne : ""} },//13437
{"code_exception.java.code.Text": { $exists : true, $ne : ""} },//13192
{"code_exception.java_1.code.Text": { $exists : true, $ne : ""} }//12951
]}
db.collection.find(rerun).count()//14093
I am able to get the documents which has some "Text" field present it as shown above
Now, I want to store "Text" for each processed document and update another field "Name" with it in that document. I've a hard time getting this logic written in query.
Failed Attempt:
db.collection.find(rerun).forEach(function(document) {
db.collection.update(
{ "_id": document._id },
{ "$set": { "Name": document.code_exception.java_*.code.Text } }
);
})
*
is to substitute with a number [40,15,10,2,4,1, ]. I know this won't work, but can anyone suggest a way obtaining the matched value for "Text" among the $ORs?
For example
doc1
in collection if matched with"code_exception.java_15.code.Text":{ $exists : true, $ne : ""}
criteria, so it's able to store"code_exception.java_15.code.Text"
on the fly and update in "Name" filed for the same doc1.- Similarly,
doc2
in collection if matched with"code_exception.java.code.Text":{ $exists : true, $ne : ""}
criteria, so it's able to store"code_exception.java.code.Text"
on the fly and update in "Name" filed for the same doc1.
Got a simple hack!
Since I need to update a field name
in the collection if I am able to find Text
corresponding to code_exception.java_*.code.Text
, where * could be a number [40,15,10,2,4,1, ] which make above fields.
The solution would be to run each filter separately and update Name
field. There would be redundant updates for sure, but that won't be a problem since, if some docs are missed by java_40.code
, it could be filled by java_1.code
or other filters.
My hack using pymongo client:
import pymongo
uri= "<URI>>"
client = pymongo.MongoClient(uri)
filter = { "$and": [
{"code_exception.java_1.code.Text": { "$exists" : True, "$ne" : "" } },
# {"code_exception.java_15.code.Text":{ $exists : true, $ne : ""} },
# {"code_exception.java_10.code.Text":{ $exists : true, $ne : ""} },
# {"code_exception.java_2.code.Text": { $exists : true, $ne : ""} },
# {"code_exception.java_4.code.Text": { $exists : true, $ne : ""} },
# {"code_exception.java.code.Text": { $exists : true, $ne : ""} },
# {"code_exception.java_1.code.Text": { $exists : true, $ne : ""} }
]}
docs = client["<db_name>"]["<coll_name>"].find(filter, no_cursor_timeout=True).batch_size(25)
collection = client["<db_name>"]["<coll_name>"]
def update_coll():
line_count = 0
for doc in docs:
line_count += 1
getText = doc["code_exception"]["java_1"]["code"]["Text"]
collection.find_one_and_update({"_id": doc['_id']}, {"$set": {"Name": getText}})
print(line_count)
if __name__ == '__main__':
update_coll()
Will execute above code 7 times once for each filter and update Name
field!
Does anyone have a better solution?
来源:https://stackoverflow.com/questions/58831053/how-to-store-update-matching-values-based-on-or-operator-in-mongodb