@@ -2354,3 +2354,128 @@ func TestRoundTripNestedFieldsCSV(t *testing.T) {
23542354 assert .EqualValues (t , tc .count , n , tc .msg )
23552355 }
23562356}
2357+
2358+ // TestRoundTripQuery verifies that mongoexport --query and --queryFile filter
2359+ // export output correctly across multiple query types.
2360+ func TestRoundTripQuery (t * testing.T ) {
2361+ testtype .SkipUnlessTestType (t , testtype .IntegrationTestType )
2362+
2363+ const dbName = "mongoimport_roundtrip_query_test"
2364+
2365+ sessionProvider , _ , err := testutil .GetBareSessionProvider ()
2366+ require .NoError (t , err )
2367+ client , err := sessionProvider .GetSession ()
2368+ require .NoError (t , err )
2369+ t .Cleanup (func () {
2370+ if err := client .Database (dbName ).Drop (context .Background ()); err != nil {
2371+ t .Errorf ("dropping test database: %v" , err )
2372+ }
2373+ })
2374+
2375+ db := client .Database (dbName )
2376+
2377+ basicDocs := []any {
2378+ bson.D {{"a" , int32 (1 )}, {"x" , bson.D {{"b" , "1" }}}},
2379+ bson.D {{"a" , int32 (2 )}, {"x" , bson.D {{"b" , "1" }, {"c" , "2" }}}},
2380+ bson.D {{"a" , int32 (1 )}, {"c" , "1" }},
2381+ bson.D {{"a" , int32 (2 )}, {"c" , "2" }},
2382+ }
2383+
2384+ n := exportAndImportWithQuery (t , db , basicDocs , `{"a":3}` , "" )
2385+ assert .EqualValues (t , 0 , n , "query matching nothing should export 0 docs" )
2386+
2387+ n = exportAndImportWithQuery (t , db , basicDocs , `{"a":1,"c":"1"}` , "" )
2388+ assert .EqualValues (t , 1 , n , "query matching one doc should export 1 doc" )
2389+
2390+ queryFile , err := os .CreateTemp (t .TempDir (), "query-*.json" )
2391+ require .NoError (t , err )
2392+ _ , err = queryFile .WriteString (`{"a":1,"c":"1"}` )
2393+ require .NoError (t , err )
2394+ require .NoError (t , queryFile .Close ())
2395+ n = exportAndImportWithQuery (t , db , basicDocs , "" , queryFile .Name ())
2396+ assert .EqualValues (t , 1 , n , "queryFile matching one doc should export 1 doc" )
2397+
2398+ n = exportAndImportWithQuery (t , db , basicDocs , `{"a":2,"x.c":"2"}` , "" )
2399+ assert .EqualValues (t , 1 , n , "query on embedded doc field should export 1 doc" )
2400+
2401+ n = exportAndImportWithQuery (t , db , basicDocs , `{}` , "" )
2402+ assert .EqualValues (t , 4 , n , "empty query should export all 4 docs" )
2403+
2404+ // TOOLS-469: extended JSON date query with $numberLong
2405+ dateDocs := []any {bson.D {
2406+ {"a" , int32 (1 )},
2407+ {"x" , bson .NewDateTimeFromTime (time .Date (2014 , 12 , 11 , 13 , 52 , 39 , 498000000 , time .UTC ))},
2408+ {"y" , bson .NewDateTimeFromTime (time .Date (2014 , 12 , 13 , 13 , 52 , 39 , 498000000 , time .UTC ))},
2409+ }}
2410+ dateQueryNumberLong := `{
2411+ "x": {
2412+ "$gt": {"$date": {"$numberLong": "1418305949498"}},
2413+ "$lt": {"$date": {"$numberLong": "1418305979498"}}
2414+ },
2415+ "y": {
2416+ "$gt": {"$date": {"$numberLong": "1418478749498"}},
2417+ "$lt": {"$date": {"$numberLong": "1418478769498"}}
2418+ }
2419+ }`
2420+ n = exportAndImportWithQuery (t , db , dateDocs , dateQueryNumberLong , "" )
2421+ assert .EqualValues (t , 1 , n , "extended JSON date query should export 1 doc" )
2422+
2423+ // TOOLS-530: date query with ISO string format
2424+ n = exportAndImportWithQuery (
2425+ t ,
2426+ db ,
2427+ dateDocs ,
2428+ `{"x":{"$gt":{"$date":"2014-12-11T13:52:39.3Z"},"$lt":{"$date":"2014-12-11T13:52:39.5Z"}}}` ,
2429+ "" ,
2430+ )
2431+ assert .EqualValues (t , 1 , n , "ISO date string query should export 1 doc" )
2432+ }
2433+
2434+ func exportAndImportWithQuery (
2435+ t * testing.T ,
2436+ db * mongo.Database ,
2437+ sourceDocs []any ,
2438+ query , queryFile string ,
2439+ ) int64 {
2440+ t .Helper ()
2441+ dbName := db .Name ()
2442+ require .NoError (t , db .Collection ("source" ).Drop (t .Context ()))
2443+ require .NoError (t , db .Collection ("dest" ).Drop (t .Context ()))
2444+ if len (sourceDocs ) > 0 {
2445+ _ , err := db .Collection ("source" ).InsertMany (t .Context (), sourceDocs )
2446+ require .NoError (t , err )
2447+ }
2448+ exportToolOptions , err := testutil .GetToolOptions ()
2449+ require .NoError (t , err )
2450+ exportToolOptions .Namespace = & options.Namespace {DB : dbName , Collection : "source" }
2451+ me , err := mongoexport .New (mongoexport.Options {
2452+ ToolOptions : exportToolOptions ,
2453+ OutputFormatOptions : & mongoexport.OutputFormatOptions {
2454+ Type : "json" , JSONFormat : "relaxed" ,
2455+ },
2456+ InputOptions : & mongoexport.InputOptions {Query : query , QueryFile : queryFile },
2457+ })
2458+ require .NoError (t , err )
2459+ defer me .Close ()
2460+ tmpFile , err := os .CreateTemp (t .TempDir (), "export-*.json" )
2461+ require .NoError (t , err )
2462+ _ , err = me .Export (tmpFile )
2463+ require .NoError (t , err )
2464+ require .NoError (t , tmpFile .Close ())
2465+
2466+ importToolOptions , err := testutil .GetToolOptions ()
2467+ require .NoError (t , err )
2468+ importToolOptions .Namespace = & options.Namespace {DB : dbName , Collection : "dest" }
2469+ mi , err := New (Options {
2470+ ToolOptions : importToolOptions ,
2471+ InputOptions : & InputOptions {File : tmpFile .Name (), ParseGrace : "stop" },
2472+ IngestOptions : & IngestOptions {},
2473+ })
2474+ require .NoError (t , err )
2475+ _ , _ , err = mi .ImportDocuments ()
2476+ require .NoError (t , err )
2477+
2478+ n , err := db .Collection ("dest" ).CountDocuments (t .Context (), bson.D {})
2479+ require .NoError (t , err )
2480+ return n
2481+ }
0 commit comments