Error encountered in Typescript while attempting to $set a subdocument key value in MongoDB

This is a sample data entry.

{
    _id: ObjectId('63e501cc2054071132171098'),
    name: 'Ricky',
    discriminator: 7706,
    registerTime: ISODate('2023-02-09T14:23:08.159Z'),
    friends: {
        '63e502f4e196ec7c04c4351e': {
            friendId: ObjectId('63e502f4e196ec7c04c4351e'),
            friendshipStatus: null,
            privateChannelId: ObjectId('63e66dd85eb6c3cc248ecc95'),
            active: true
        }
    }
}

I need to modify the "friends.63e502f4e196ec7c04c4351e.friendshipStatus" property from null to 1 without replacing the entire subdocument (I want to retain the "friendId", "privateChannelId", and "active" properties)

so far I have attempted

const friendUpdateResult = await collections.users!.updateOne(
  {
    _id: targetFriend._id,
  },
  {
    $set: {
      [`friends.${currentUser._id.toString()}.friendshipStatus`]: null,
    },
  }
);

however, the use of "$set" is causing an error

Type '{ [x: string]: null; }' is not assignable to type 'Readonly<{ [x: `friends.${string}`]: unknown; [x: `friends.${string}.friendId`]: Friend | undefined; [x: `friends.${string}.friendshipStatus`]: Friend | undefined; [x: `friends.${string}.privateChannelId`]: Friend | undefined; [x: `friends.${string}.active`]: Friend | undefined;.
'string' and '`friends.${string}.friendId`' index signatures are incompatible.
Type 'null' is not assignable to type 'Friend | undefined'.

the interface for this collection is as follows:

interface User {
  name: string;
  discriminator: number;
  registerTime: Date;
  friends: Record<string, Friend>;
}

interface Friend {
  friendId: ObjectId;
  friendshipStatus?: FriendshipEnum | null;
  privateChannelId?: ObjectId;
  active?: boolean;
}

Answer №1

Opting for dynamic values as field names is often viewed as an anti-pattern, adding unnecessary complexity to queries. However, you can utilize $objectToArray to transform friends into an array of key-value pairs. Employ $map to conditionally update the field friendshipStatus. Finally, revert back to the original format using $arrayToObject

db.collection.update({
  _id: ObjectId("63e501cc2054071132171098")
},
[
  {
    $set: {
      friends: {
        "$arrayToObject": {
          "$map": {
            "input": {
              "$objectToArray": "$friends"
            },
            "as": "f",
            "in": {
              "$cond": {
                "if": {
                  "$eq": [
                    "$$f.k",
                    "63e502f4e196ec7c04c4351e"
                  ]
                },
                "then": {
                  "$mergeObjects": [
                    "$$f",
                    {
                      v: {
                        "$mergeObjects": [
                          "$$f.v",
                          {
                            "friendshipStatus": 1
                          }
                        ]
                      }
                    }
                  ]
                },
                "else": "$$f"
              }
            }
          }
        }
      }
    }
  }
])

Mongo Playground


If redesigning the schema is on the table, consider restructuring it like this:

[
  {
    _id: ObjectId("63e501cc2054071132171098"),
    name: "Ricky",
    discriminator: 7706,
    registerTime: ISODate("2023-02-09T14:23:08.159Z"),
    friends: [
      {
        friendId: ObjectId("63e502f4e196ec7c04c4351e"),
        friendshipStatus: null,
        privateChannelId: ObjectId("63e66dd85eb6c3cc248ecc95"),
        active: true
      }
    ]
  }
]

You can then index the friends.friendId field to enhance performance.

The query will be simplified to:

db.collection.update({
  _id: ObjectId("63e501cc2054071132171098"),
  "friends.friendId": ObjectId("63e502f4e196ec7c04c4351e")
},
{
  $set: {
    "friends.$.friendshipStatus": 1
  }
})

Mongo Playground

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring composite search conditions in MongoDB with JavaScript

Being a newcomer to Node JS and mongo DB, I am currently working on a project that involves fetching data from mongo db using a JavaScript file. The challenge I am facing is to search multiple columns in order to retrieve the desired results. Initially, w ...

Creating a versatile TypeScript Record that can accommodate multiple data types

I have a question regarding the use of Record in TypeScript. When I specify Record as the parameter type in a function, I encounter an error in my code because it does not allow different types. type Keys = 'name' | 'qty'; const getVal ...

Issue encountered while attempting to package Azure project in Visual Studio 2015 Update1 due to difficulty copying Typescript files

Since upgrading to VS 2015 Update 1 (that includes Typescript 1.7) and Azure SDK 2.8, packaging my Azure application for deployment has become a challenge due to an error in the file path where the packager is attempting to copy the js output file: Erro ...

Locate data entries that have a modulo value exceeding a specific threshold

One interesting feature in mongodb is the ability to find records where a particular field, when divided by X, equals Y: db.collection.find({ field: { $mod: [X, Y] } }) Now, what if you need to find records where the result of $mod is greater than Y? ...

Retrieve the top 5 data fields from a leaderboard in MongoDB

I am currently working with a simple table that displays data in the following format: { _id: 55dbdffeaba8ee274d3b9f89, firstname: 'Jim', lastname: 'Kirk', email: '<a href="/cdn-cgi/l/email-protection" class="__cf_e ...

Error: Module not found - Unable to locate 'dropzone'

Since migrating from Angular 4.4 to Angular 8.0, I encountered the following issue: ERROR in ./src/attributes/import/import.component.ts Module not found: Error: Can't resolve 'dropzone' in 'C:....\src\attributes\imp ...

Using Typescript, develop a function within an entity to verify the value of a property

In my Angular 7 app, I have an entity defined in my typescript file as follows: export class FeedbackType { id: number; name: String; } I am looking to create a function within this entity that checks the value of a property. For example: feedba ...

The 'picker' property is not found in the '{}' type but is necessary in the 'TimeRangePickerProps' type

I am encountering an issue while trying to implement the new RangePicker for the TimePicker of antd v4. Surprisingly, this error only occurs in my development environment and not when I try to reproduce it on codesandbox. Despite checking their documentati ...

A guide to using the up and down keys to switch focus between div elements in a react component with TypeScript and CSS

I am currently working with a scenario where data is being displayed within different div elements, and I wish to enable the selection/focus of a specific div when users use the up/down arrow keys. While trying to achieve this functionality by using refs ...

Issue with ngFor displaying only the second item in the array

There are supposed to be two editable input fields for each section, with corresponding data. However, only the second JSON from the sample is being displayed in both sections. The JSON in the TypeScript file appears as follows: this.sample = [ { "se ...

Angular, perplexed by the output displayed in the console

I'm completely new to Angular and feeling a bit lost when it comes to the console output of an Angular app. Let me show you what I've been working on so far! app.component.ts import { Component } from '@angular/core'; @Component({ ...

Encountering an undefined error while attempting to retrieve an object from an array by index in Angular

Once the page is loaded, it retrieves data on countries from my rest api. When a user selects a country, it then loads the corresponding cities for that country. Everything is functioning properly up to this point, however, upon opening the page, the city ...

Typescript: Issue encountered with Record type causing Type Error

When utilizing handler functions within an object, the Record type is used in the following code snippet: interface User { id: string; avatar: string; email: string; name: string; role?: string; [key: string]: any; } interface Stat ...

Connecting two divs with lines in Angular can be achieved by using SVG elements such as

* Tournament Brackets Tree Web Page In the process of developing a responsive tournament brackets tree web page. * Connection Challenge I am facing an issue where I need to connect each bracket, represented by individual divs, with decorative lines linki ...

Utilizing dynamic arguments in TypeScript to recycle types

Can I accomplish this with TypeScript? Here is the source code I currently have: interface FormStore<T> { type: T; } interface Form<T> extends FormStore<T> { email: T; phone: T; password: T; } interface FormState<R> { fo ...

Are the functions 'useEffect' and 'useCallback' being repetitively used in this case?

I have implemented a custom hook in my React application to manage back navigation actions (POP). The functionality is operational, but I can't help but notice that useCallback and useEffect seem to be performing similar tasks. Here is the snippet of ...

Adding ngrx action class to reducer registration

Looking to transition my ngrx actions from createAction to a class-based approach, but encountering an error in the declaration of the action within the associated reducer: export enum ActionTypes { LOAD_PRODUCTS_FROM_API = '[Products] Load Products ...

Utilizing the <HTMLSelectElement> in a Typescript project

What exactly does the <HTMLSelectElement> do in relation to a TypeScript task? let element = <HTMLSelectElement> document.querySelector('#id_name'); The HTMLSelectElement interface, similar to the one mentioned in TypeScript, is exp ...

What is the best way to access the input element of ng-content from the parent component?

Creating a unique component in the following structure <div class="custom-search-field" [ngClass]="{'expanding': expanding}"> <ng-content></ng-content> </div> When using this component, users are expected to include ...

Transitioning an NX environment to integrate ESM

My NX-based monorepo is quite extensive, consisting of half a dozen apps, frontend, backend, and dozens of libs. Currently, everything is set up to use commonjs module types, as that's what the NX generators have always produced. However, many librar ...