@@ -1997,3 +1997,113 @@ func exportCSVAndImport(t *testing.T, dbName, exportFields string, db *mongo.Dat
19971997 _ , _ , err = mi .ImportDocuments ()
19981998 require .NoError (t , err )
19991999}
2000+
2001+ // TestRoundTripFieldsJSON verifies that mongoexport --fields limits which fields
2002+ // appear in JSON export output, and that _id is included (unlike CSV).
2003+ func TestRoundTripFieldsJSON (t * testing.T ) {
2004+ testtype .SkipUnlessTestType (t , testtype .IntegrationTestType )
2005+
2006+ const dbName = "mongoimport_roundtrip_fieldsjson_test"
2007+
2008+ sessionProvider , _ , err := testutil .GetBareSessionProvider ()
2009+ require .NoError (t , err )
2010+ client , err := sessionProvider .GetSession ()
2011+ require .NoError (t , err )
2012+ t .Cleanup (func () {
2013+ if err := client .Database (dbName ).Drop (context .Background ()); err != nil {
2014+ t .Errorf ("dropping test database: %v" , err )
2015+ }
2016+ })
2017+
2018+ db := client .Database (dbName )
2019+ _ , err = db .Collection ("source" ).InsertMany (t .Context (), []any {
2020+ bson.D {{"a" , int32 (1 )}},
2021+ bson.D {{"a" , int32 (1 )}, {"b" , int32 (1 )}},
2022+ bson.D {{"a" , int32 (1 )}, {"b" , int32 (2 )}, {"c" , int32 (3 )}},
2023+ })
2024+ require .NoError (t , err )
2025+
2026+ exportJSONAndImport (t , dbName , "a" , db )
2027+ dest := db .Collection ("dest" )
2028+ n , err := dest .CountDocuments (t .Context (), bson.D {{"a" , int32 (1 )}})
2029+ require .NoError (t , err )
2030+ assert .EqualValues (t , 3 , n , "3 documents should have a=1" )
2031+ n , err = dest .CountDocuments (t .Context (), bson.D {{"b" , int32 (1 )}})
2032+ require .NoError (t , err )
2033+ assert .EqualValues (t , 0 , n , "b=1 should not have been exported" )
2034+ n , err = dest .CountDocuments (t .Context (), bson.D {{"b" , int32 (2 )}})
2035+ require .NoError (t , err )
2036+ assert .EqualValues (t , 0 , n , "b=2 should not have been exported" )
2037+ n , err = dest .CountDocuments (t .Context (), bson.D {{"c" , int32 (3 )}})
2038+ require .NoError (t , err )
2039+ assert .EqualValues (t , 0 , n , "c=3 should not have been exported" )
2040+
2041+ exportJSONAndImport (t , dbName , "a,b,c" , db )
2042+ n , err = dest .CountDocuments (t .Context (), bson.D {{"a" , int32 (1 )}})
2043+ require .NoError (t , err )
2044+ assert .EqualValues (t , 3 , n , "3 documents should have a=1" )
2045+ n , err = dest .CountDocuments (t .Context (), bson.D {{"b" , int32 (1 )}})
2046+ require .NoError (t , err )
2047+ assert .EqualValues (t , 1 , n , "1 document should have b=1" )
2048+ n , err = dest .CountDocuments (t .Context (), bson.D {{"b" , int32 (2 )}})
2049+ require .NoError (t , err )
2050+ assert .EqualValues (t , 1 , n , "1 document should have b=2" )
2051+ n , err = dest .CountDocuments (t .Context (), bson.D {{"c" , int32 (3 )}})
2052+ require .NoError (t , err )
2053+ assert .EqualValues (t , 1 , n , "1 document should have c=3" )
2054+
2055+ var fromSource , fromDest bson.M
2056+ q := bson.D {{"a" , int32 (1 )}, {"b" , int32 (1 )}}
2057+ err = db .Collection ("source" ).FindOne (t .Context (), q ).Decode (& fromSource )
2058+ require .NoError (t , err )
2059+ err = dest .FindOne (t .Context (), q ).Decode (& fromDest )
2060+ require .NoError (t , err )
2061+ assert .Equal (
2062+ t , fromSource ["_id" ], fromDest ["_id" ],
2063+ "_id should have been exported in JSON mode" ,
2064+ )
2065+ }
2066+
2067+ func exportJSONAndImport (t * testing.T , dbName , fields string , db * mongo.Database ) {
2068+ t .Helper ()
2069+ require .NoError (t , db .Collection ("dest" ).Drop (t .Context ()))
2070+
2071+ tmpFile , err := os .CreateTemp (t .TempDir (), "export-*.json" )
2072+ require .NoError (t , err )
2073+ require .NoError (t , tmpFile .Close ())
2074+
2075+ exportToolOptions , err := testutil .GetToolOptions ()
2076+ require .NoError (t , err )
2077+ exportToolOptions .Namespace = & options.Namespace {DB : dbName , Collection : "source" }
2078+ me , err := mongoexport .New (mongoexport.Options {
2079+ ToolOptions : exportToolOptions ,
2080+ OutputFormatOptions : & mongoexport.OutputFormatOptions {
2081+ Type : "json" ,
2082+ JSONFormat : "canonical" ,
2083+ Fields : fields ,
2084+ },
2085+ InputOptions : & mongoexport.InputOptions {},
2086+ })
2087+ require .NoError (t , err )
2088+ defer me .Close ()
2089+ f , err := os .OpenFile (tmpFile .Name (), os .O_WRONLY , 0o644 )
2090+ require .NoError (t , err )
2091+ _ , err = me .Export (f )
2092+ require .NoError (t , err )
2093+ require .NoError (t , f .Close ())
2094+
2095+ importToolOptions , err := testutil .GetToolOptions ()
2096+ require .NoError (t , err )
2097+ importToolOptions .Namespace = & options.Namespace {DB : dbName , Collection : "dest" }
2098+ mi , err := New (Options {
2099+ ToolOptions : importToolOptions ,
2100+ InputOptions : & InputOptions {
2101+ File : tmpFile .Name (),
2102+ ParseGrace : "stop" ,
2103+ },
2104+ IngestOptions : & IngestOptions {},
2105+ })
2106+ require .NoError (t , err )
2107+ _ , _ , err = mi .ImportDocuments ()
2108+ require .NoError (t , err )
2109+ }
0 commit comments