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