@@ -30,6 +30,7 @@ import (
3030 "github.com/stretchr/testify/assert"
3131 "github.com/stretchr/testify/require"
3232 "go.mongodb.org/mongo-driver/v2/bson"
33+ "go.mongodb.org/mongo-driver/v2/mongo"
3334 mopt "go.mongodb.org/mongo-driver/v2/mongo/options"
3435)
3536
@@ -1885,3 +1886,114 @@ func TestRoundTripFieldFile(t *testing.T) {
18851886 require .NoError (t , err )
18861887 assert .EqualValues (t , 0 , n , "c=3 should not have been exported (not in fieldFile)" )
18871888}
1889+
1890+ // TestRoundTripFieldsCSV verifies that mongoexport --csv --fields limits which
1891+ // fields are exported, and that mongoimport correctly restores the filtered data.
1892+ // Covers the first two scenarios of fields_csv.js.
1893+ func TestRoundTripFieldsCSV (t * testing.T ) {
1894+ testtype .SkipUnlessTestType (t , testtype .IntegrationTestType )
1895+
1896+ const dbName = "mongoimport_roundtrip_fieldscsv_test"
1897+
1898+ sessionProvider , _ , err := testutil .GetBareSessionProvider ()
1899+ require .NoError (t , err )
1900+ client , err := sessionProvider .GetSession ()
1901+ require .NoError (t , err )
1902+ t .Cleanup (func () {
1903+ if err := client .Database (dbName ).Drop (context .Background ()); err != nil {
1904+ t .Errorf ("dropping test database: %v" , err )
1905+ }
1906+ })
1907+
1908+ db := client .Database (dbName )
1909+ _ , err = db .Collection ("source" ).InsertMany (t .Context (), []any {
1910+ bson.D {{"a" , int32 (1 )}},
1911+ bson.D {{"a" , int32 (1 )}, {"b" , int32 (1 )}},
1912+ bson.D {{"a" , int32 (1 )}, {"b" , int32 (2 )}, {"c" , int32 (3 )}},
1913+ })
1914+ require .NoError (t , err )
1915+
1916+ exportCSVAndImport (t , dbName , "a" , db )
1917+ dest := db .Collection ("dest" )
1918+ n , err := dest .CountDocuments (t .Context (), bson.D {{"a" , int32 (1 )}})
1919+ require .NoError (t , err )
1920+ assert .EqualValues (t , 3 , n , "3 documents should have a=1" )
1921+ n , err = dest .CountDocuments (t .Context (), bson.D {{"b" , int32 (1 )}})
1922+ require .NoError (t , err )
1923+ assert .EqualValues (t , 0 , n , "b=1 should not have been exported" )
1924+ n , err = dest .CountDocuments (t .Context (), bson.D {{"b" , int32 (2 )}})
1925+ require .NoError (t , err )
1926+ assert .EqualValues (t , 0 , n , "b=2 should not have been exported" )
1927+ n , err = dest .CountDocuments (t .Context (), bson.D {{"c" , int32 (3 )}})
1928+ require .NoError (t , err )
1929+ assert .EqualValues (t , 0 , n , "c=3 should not have been exported" )
1930+
1931+ exportCSVAndImport (t , dbName , "a,b,c" , db )
1932+ n , err = dest .CountDocuments (t .Context (), bson.D {{"a" , int32 (1 )}})
1933+ require .NoError (t , err )
1934+ assert .EqualValues (t , 3 , n , "3 documents should have a=1" )
1935+ n , err = dest .CountDocuments (t .Context (), bson.D {{"b" , int32 (1 )}})
1936+ require .NoError (t , err )
1937+ assert .EqualValues (t , 1 , n , "1 document should have b=1" )
1938+ n , err = dest .CountDocuments (t .Context (), bson.D {{"b" , int32 (2 )}})
1939+ require .NoError (t , err )
1940+ assert .EqualValues (t , 1 , n , "1 document should have b=2" )
1941+ n , err = dest .CountDocuments (t .Context (), bson.D {{"c" , int32 (3 )}})
1942+ require .NoError (t , err )
1943+ assert .EqualValues (t , 1 , n , "1 document should have c=3" )
1944+
1945+ var fromSource , fromDest bson.M
1946+ q := bson.D {{"a" , int32 (1 )}, {"b" , int32 (1 )}}
1947+ err = db .Collection ("source" ).FindOne (t .Context (), q ).Decode (& fromSource )
1948+ require .NoError (t , err )
1949+ err = dest .FindOne (t .Context (), q ).Decode (& fromDest )
1950+ require .NoError (t , err )
1951+ assert .NotEqual (t , fromSource ["_id" ], fromDest ["_id" ], "_id should not have been exported" )
1952+ }
1953+
1954+ func exportCSVAndImport (t * testing.T , dbName , exportFields string , db * mongo.Database ) {
1955+ t .Helper ()
1956+ require .NoError (t , db .Collection ("dest" ).Drop (t .Context ()))
1957+
1958+ exportTarget , err := os .CreateTemp (t .TempDir (), "export-*.csv" )
1959+ require .NoError (t , err )
1960+ require .NoError (t , exportTarget .Close ())
1961+
1962+ exportToolOptions , err := testutil .GetToolOptions ()
1963+ require .NoError (t , err )
1964+ exportToolOptions .Namespace = & options.Namespace {DB : dbName , Collection : "source" }
1965+ me , err := mongoexport .New (mongoexport.Options {
1966+ ToolOptions : exportToolOptions ,
1967+ OutputFormatOptions : & mongoexport.OutputFormatOptions {
1968+ Type : "csv" ,
1969+ JSONFormat : "canonical" ,
1970+ Fields : exportFields ,
1971+ },
1972+ InputOptions : & mongoexport.InputOptions {},
1973+ })
1974+ require .NoError (t , err )
1975+ defer me .Close ()
1976+ f , err := os .OpenFile (exportTarget .Name (), os .O_WRONLY , 0o644 )
1977+ require .NoError (t , err )
1978+ _ , err = me .Export (f )
1979+ require .NoError (t , err )
1980+ require .NoError (t , f .Close ())
1981+
1982+ importFields := "a,b,c"
1983+ importToolOptions , err := testutil .GetToolOptions ()
1984+ require .NoError (t , err )
1985+ importToolOptions .Namespace = & options.Namespace {DB : dbName , Collection : "dest" }
1986+ mi , err := New (Options {
1987+ ToolOptions : importToolOptions ,
1988+ InputOptions : & InputOptions {
1989+ File : exportTarget .Name (),
1990+ Type : "csv" ,
1991+ Fields : & importFields ,
1992+ ParseGrace : "stop" ,
1993+ },
1994+ IngestOptions : & IngestOptions {},
1995+ })
1996+ require .NoError (t , err )
1997+ _ , _ , err = mi .ImportDocuments ()
1998+ require .NoError (t , err )
1999+ }
0 commit comments