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