@@ -237,6 +237,58 @@ func Unmarshal(data []byte) (*types.Document, error) {
237237 return d , nil
238238}
239239
240+ // UnmarshalFields decodes only selected top-level fields. It still parses the
241+ // complete outer JSON object, but avoids recursively decoding unobservable
242+ // values and their often much larger schemas (for example member arrays when a
243+ // client requested only _id). Missing selected fields remain missing.
244+ func UnmarshalFields (data []byte , fields []string ) (* types.Document , error ) {
245+ var values map [string ]json.RawMessage
246+ if err := json .Unmarshal (data , & values ); err != nil {
247+ return nil , lazyerrors .Error (err )
248+ }
249+
250+ jsch , ok := values ["$s" ]
251+ if ! ok {
252+ return nil , lazyerrors .Errorf ("schema is not set" )
253+ }
254+ var sch struct {
255+ Properties map [string ]json.RawMessage `json:"p"`
256+ Keys []string `json:"$k"`
257+ }
258+ if err := json .Unmarshal (jsch , & sch ); err != nil {
259+ return nil , lazyerrors .Error (err )
260+ }
261+
262+ wanted := make (map [string ]struct {}, len (fields ))
263+ for _ , field := range fields {
264+ wanted [field ] = struct {}{}
265+ }
266+ d := must .NotFail (types .NewDocument ())
267+ for _ , key := range sch .Keys {
268+ if _ , ok := wanted [key ]; ! ok {
269+ continue
270+ }
271+ value , exists := values [key ]
272+ if ! exists {
273+ return nil , lazyerrors .Errorf ("sjson.UnmarshalFields: missing key %q" , key )
274+ }
275+ rawElem , exists := sch .Properties [key ]
276+ if ! exists {
277+ return nil , lazyerrors .Errorf ("sjson.UnmarshalFields: missing schema for key %q" , key )
278+ }
279+ var fieldSchema elem
280+ if err := json .Unmarshal (rawElem , & fieldSchema ); err != nil {
281+ return nil , lazyerrors .Error (err )
282+ }
283+ decoded , err := unmarshalSingleValue (value , & fieldSchema )
284+ if err != nil {
285+ return nil , lazyerrors .Error (err )
286+ }
287+ d .Set (key , decoded )
288+ }
289+ return d , nil
290+ }
291+
240292// unmarshalSingleValue decodes the given sjson-encoded data element by the given schema.
241293func unmarshalSingleValue (data json.RawMessage , sch * elem ) (any , error ) {
242294 if bytes .Equal (data , []byte ("null" )) {
0 commit comments