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