我有一个来自mongo db更改流的bson_t“ b”,由bson_as_canonical_extended_json这样打印:
{ "_id" : { "_data" : "825ECC4FEA0000002E2B022C0100296E5A10044A1DE2ECB8554397B8F
03E803FB80F1F463C5F6964003C3030313330323637000004" },
"operationType" : "update",
"clusterTime" : { "$timestamp" : { "t" : 1590448106, "i" : 46 } },
"ns" : { "db" : "test", "coll" : "my_collection" },
"documentKey" : { "_id" : "00130267" },
"updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" },
"removedFields" : [ ] } }
我可以这样进入“ documentKey”字段:
bson_iter_t iter;
if (bson_iter_init_find(&iter, b, "documentKey"))
bson_iter_t child;
if (bson_iter_recurse(&iter, &child))
{
while (bson_iter_next(&child))
{
const bson_value_t *value = bson_iter_value(&child);
printf("documentKey sub-key %s value %s\n", bson_iter_key(&child), (char*)value->value.v_utf8.str);
}
}
打印“ _id”:“ 00130267”如何访问“ updateDescription”字段,到处都有示例这个结构不是我选择的,它来自mongo db change stream
鲍曼(Bauman)后来的回答更加严格,对我来说,这是可行的:
bson_iter_t iter1;
if (bson_iter_init_find(&iter1, b, "updateDescription")) // doc
{
bson_iter_t child1;
if (bson_iter_recurse(&iter1, &child1))
{
while (bson_iter_next(&child1))// updatedFields doc
{
bson_iter_t child2;
bson_iter_recurse(&child1, &child2);
while (bson_iter_next(&child2))
{
const bson_value_t *value = bson_iter_value(&child2);
printf("updateDescription arr %s value %s\n", bson_iter_key(&child2), (char*)value->value.v_utf8.str);// key and value of the array
}
}
}
}
#include <bson.h>
void descending_to_updateDescription(bson_t *b){
bson_iter_t change_iter;
if (bson_iter_init_find(&change_iter, b, "updateDescription"))
{
bson_iter_t desired_field;
if (bson_iter_recurse(&change_iter, &desired_field))
{
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value)
// pointer is now here | (at the beginning of the document
// confirm the (value) is type DOCUMENT as we expect (containing keys, "updateFields" and "removedFields"
if BSON_ITER_HOLDS_DOCUMENT(&change_iter){
while (bson_iter_next(&desired_field))
{
// printing the outer key (expect 2, shown below)
printf("%s\n", bson_iter_key(&desired_field));
// first loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) -- another document
// pointer is now here ----------------- |
//
// next loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) - a list
// pointer is now waaaaaaaaaayyyyyyyy ovvvvvveeeeerrr here --------------------------------------------------- |
// next loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// ^
// pointer is now waaaaaaaaaayyyyyyyy ovvvvvveeeeerrr here ---------------------------------------------------------- | (end of document
// iter_next returns false, because no other keys in the outer dict
// descend into the next level down
bson_iter_t changefields_iter;
// SUPER IMPORTANT, recurese from desired_field, not from the original change iter!
if (bson_iter_recurse(&desired_field, &changefields_iter)){
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) - a document
// pointer is now here -------------------- |
// expect update fields to hold a documnet, and removeFields to hold a list, skip processing remove fields
while (bson_iter_next(&changefields_iter)) {
// first loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) - a string in this example
// pointer is now here --------------------------------|
// second loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// (key) ^ (value) - a string in this example
// pointer is now here --------------------------------------------------------|
// third loop
// "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] }
// ^
// pointer is now here ----------------------------------------------------------------------| (end of document)
// Example looks like we expect string values, so check for it
if (BSON_ITER_HOLDS_UTF8(&changefields_iter)){
uint32_t length; // iterating the string object can give you length, we don't need it though because we're not strncopying
printf(
"\tKey: %s \t Value: %s\n",
bson_iter_key(&changefields_iter),
bson_iter_utf8(&changefields_iter, &length)
);
}
}
}
}
}
}
}
}
int main(){
// just setting up
char * json_data = "{ \"_id\" : { \"_data\" : \"825ECC4FEA0000002E2B022C0100296E5A10044A1DE2ECB8554397B8F03E803FB80F1F463C5F6964003C3030313330323637000004\" }, \"operationType\" : \"update\", \"clusterTime\" : { \"$timestamp\" : { \"t\" : 1590448106, \"i\" : 46 } }, \"ns\" : { \"db\" : \"test\", \"coll\" : \"my_collection\" }, \"documentKey\" : { \"_id\" : \"00130267\" }, \"updateDescription\" : { \"updatedFields\" : { \"0x000F\" : \"25.006001\", \"0x0010\" : \"24.976000\" }, \"removedFields\" : [ ] } }" ;
bson_error_t error;
bson_t *b;
b = bson_new_from_json ((uint8_t*)json_data, -1, &error);
descending_to_updateDescription(b);
bson_destroy(b);
b = NULL; // explicit nulled in case this is extended later
return 0;
}
这是输出
updatedFields
Key: 0x000F Value: 25.006001
Key: 0x0010 Value: 24.976000
removedFields
Process finished with exit code 0
重要的事实是第二次下降。
当您找到并递归到updateDescription时,还需要再次下降到UpdatedFields / updatedFields文档中,以将其打印出来。
[此外,如果您真的只想检查“ updateFields”,则可以始终使用dot notation和find_descendant函数将显式的while循环转换为隐式(执行的库)。您的代码看起来更简洁,但是您这样做并没有节省任何性能,该库正在执行与上例相同的循环
#include <bson.h> void descending_direct_to_updateFields(bson_t *b){ bson_iter_t change_iter; bson_iter_t updateFields_iter; // use the find_descendant function if (bson_iter_init(&change_iter, b) && bson_iter_find_descendant(&change_iter, "updateDescription.updatedFields", &updateFields_iter)) { // "updateDescription" : { "updatedFields" : { "0x000F" : "25.006001", "0x0010" : "24.976000" }, "removedFields" : [ ] } // (key) ^ (value) - document with 2 keys // pointer is now here -------------------| printf("%s\n", "updateDescription.updatedFields"); // just print because you looked for it if BSON_ITER_HOLDS_DOCUMENT(&updateFields_iter){ bson_iter_t desired_field; bson_iter_recurse(&updateFields_iter, &desired_field); while (bson_iter_next(&desired_field)) { if (BSON_ITER_HOLDS_UTF8(&desired_field)) { uint32_t length; // iterating the string object can give you length, we don't need it though because we're not strncopying printf( "\tKey: %s \t Value: %s\n", bson_iter_key(&desired_field), bson_iter_utf8(&desired_field, &length) ); } } } } } int main(){ // just setting up char * json_data = "{ \"_id\" : { \"_data\" : \"825ECC4FEA0000002E2B022C0100296E5A10044A1DE2ECB8554397B8F03E803FB80F1F463C5F6964003C3030313330323637000004\" }, \"operationType\" : \"update\", \"clusterTime\" : { \"$timestamp\" : { \"t\" : 1590448106, \"i\" : 46 } }, \"ns\" : { \"db\" : \"test\", \"coll\" : \"my_collection\" }, \"documentKey\" : { \"_id\" : \"00130267\" }, \"updateDescription\" : { \"updatedFields\" : { \"0x000F\" : \"25.006001\", \"0x0010\" : \"24.976000\" }, \"removedFields\" : [ ] } }" ; bson_error_t error; bson_t *b; b = bson_new_from_json ((uint8_t*)json_data, -1, &error); descending_direct_to_updateFields(b); bson_destroy(b); b = NULL; // explicit nulled in case this is extended later return 0; }
这是输出
updateDescription.updatedFields Key: 0x000F Value: 25.006001 Key: 0x0010 Value: 24.976000
堆栈溢出默认为这些答案提供了一个过度保护的许可证。在允许的范围内,我将所有答案中的所有代码和单词都放入了公共领域。在不允许或不承认公共领域的情况下,代码和文字与libbson本身使用的许可相同。