How do I update the data in an object that is in an array?

const DB_URL = 'mongodb+srv://*****:********@cluster0.ptvwi.mongodb.net/*****?retryWrites=true&w=majority'
const mongo = require('mongoose');
mongo.connect(DB_URL);

var User = mongo.model('User', {
	id: Number,
	balance: Number,
	trees: Array,
});
user.trees.push({ id: tree.id, poken: 0});

Hello @qwert_yuiop, Welcome to MongoDB community forum,

You can use such array operators as defined in the below docs,

And you can follow the update query instruction in below docs,

for a more specific solution please share the exact use case and requirement with details.

Here I would like to change it to poken: 7 in the object with poken: 5

Database_name.Collection_name.trees
{
   "0":"Object" {
      "id": 0,
      "poken": 5
   },
   "1":"Object" {
      "id": 1,
      "poken":7
   }
}

It is not clear to me, could you please explain more, if possible, please add a valid JSON document.

Hi @qwert_yuiop,

If I understand correctly your example doc should look like:

var doc = {
    "_id": 1,
    "balance": 100,
    "trees": [
        { "id": 0, "poken": 5},
        { "id": 1, "poken": 7}
    ]
}

I think what you are looking for is the $elemMatch query operator which can be used to find the first matching element of an array and can be combined with the positional operator ($) in an update query.

For example, using the MongoDB Shell:

test> db.data.insertOne(doc)
{ acknowledged: true, insertedId: 1 }

test> db.data.findOne()
{
  _id: 1,
  balance: 100,
  trees: [ { id: 0, poken: 5 }, { id: 1, poken: 7 } ]
}

test> db.data.updateOne(

	// $elemMatch finds docs containing an array with a matching element
	{
		"trees": { "$elemMatch": { "poken": 5 }}
	},

	// Positional operator $ is a placeholder for the first matching array element
	{
		"$set": { "trees.$.poken": 7 }
	}
);
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}

test> db.data.findOne()
{
  _id: 1,
  balance: 100,
  trees: [ { id: 0, poken: 7 }, { id: 1, poken: 7 } ]
}

If that isn’t what you’re trying to achieve, please provide more specific details including a valid document to test with and an example of the desired result.

The Array Update Operators documentation linked in @turivishal’s comment covers other available operators for updating arrays.

Regards,
Stennie

4 Likes

Maybe a mistake somewhere, but it didn’t work
message.user.updateOne(

        	// $elemMatch finds docs containing an array with a matching element
        	{
        		"trees": { "$elemMatch": { "poken": 5 }}
        	},
        
        	// Positional operator $ is a placeholder for the first matching array element
        	{
        		"$set": { "trees.$.poken": 7 }
        	}
        );

You are accessing db.data, and I somehow also need to access the database?

It contains only the id of the users of my telegram bot
maybe it will help?

<ref *1> Mongoose {
  connections: [
    NativeConnection {
      base: [Circular *1],
      collections: [Object],
      models: [Object],
      config: [Object],
      replica: false,
      options: null,
      otherDbs: [],
      relatedDbs: {},
      states: [Object: null prototype],
      _readyState: 1,
      _closeCalled: false,
      _hasOpened: true,
      plugins: [],
      _listening: false,
      _connectionOptions: [Object],
      client: [MongoClient],
      '$initialConnection': [Promise],
      name: 'admin',
      host: 'cluster0-shard-00-02.ptvwi.mongodb.net',
      port: 27017,
      user: 'itest**********',
      pass: '********',
      db: [Db]
    }
  ],
  models: {
    User: Model { User },
  },
  modelSchemas: {
    User: Schema {
      obj: [Object],
      paths: [Object],
      aliases: {},
      subpaths: [Object],
      virtuals: {},
      singleNestedPaths: {},
      nested: {},
      inherits: {},
      callQueue: [],
      _indexes: [],
      methods: {},
      methodOptions: {},
      statics: {},
      tree: [Object],
      query: {},
      childSchemas: [],
      plugins: [Array],
      '$id': 1,
      s: [Object],
      _userProvidedOptions: {},
      options: [Object],
      '$globalPluginsApplied': true,
      _requiredpaths: [],
      _indexedpaths: []
    },
  },
  options: { pluralization: true },
  _pluralize: [Function: pluralize],
  Schema: [Function: Schema] {
    reserved: [Object: null prototype] {
      populated: 1,
      remove: 1,
      validate: 1,
      toObject: 1,
      schema: 1,
      save: 1,
      modelName: 1,
      get: 1,
      isNew: 1,
      isModified: 1,
      init: 1,
      errors: 1,
      db: 1,
      collection: 1,
      removeListener: 1,
      listeners: 1,
      once: 1,
      on: 1,
      emit: 1,
      prototype: 1
    },
    Types: {
      String: [Function],
      Number: [Function],
      Boolean: [Function],
      DocumentArray: [Function],
      Embedded: [Function: SingleNestedPath],
      Array: [Function],
      Buffer: [Function],
      Date: [Function],
      ObjectId: [Function],
      Mixed: [Function],
      Decimal: [Function],
      Decimal128: [Function],
      Map: [class Map extends SchemaType],
      Oid: [Function],
      Object: [Function],
      Bool: [Function],
      ObjectID: [Function]
    },
    ObjectId: [Function: ObjectId] {
      schemaName: 'ObjectId',
      get: [Function (anonymous)],
      _checkRequired: [Function (anonymous)],
      _cast: [Function: castObjectId],
      cast: [Function: cast],
      checkRequired: [Function (anonymous)]
    }
  },
  model: [Function (anonymous)],
  plugins: [
    [ [Function (anonymous)], [Object] ],
    [ [Function (anonymous)], [Object] ],
    [ [Function], [Object] ],
    [ [Function (anonymous)], [Object] ]
  ]
}

Make sure you have wrapped the query in async/await method, to wait for the response.

async function yourMethodName() {
  await message.user.updateOne(...
}

async function yourMethodName() {
await message.user.updateOne (

    	// $elemMatch finds docs containing an array with a matching element
    	{
    		"trees": { "$elemMatch": { "poken": 5 }}
    	},
    
    	// Positional operator $ is a placeholder for the first matching array element
    	{
    		"$set": { "trees.$.poken": 7 }
    	}
    );}
    yourMethodName()

Got an error
The dollar ($) prefixed field ‘$elemMatch’ in ‘trees.0.$elemMatch’ is not valid for storage.

Maybe it will help
trees : Array

  1. 0:Object
  2. id:0
  3. poken:15
  4. 1:Object
  5. id:0
  6. poken:10
  7. 2:Object
  8. id:1
  9. poken:20
  10. 3:Object
  11. id:0
  12. poken:5
  13. 4:Object
  14. id:0
  15. poken:0

There is something wrong in your implemented code, look at the working query in playground as on your input document,

Please share more details:

  • MongoDB server version
  • If you are using mongoose library then please share schema/model and controller implemented code.

I don’t know how to look at it
How do I know which version my hosting uses?
I think I use, but what should the scheme / model look like?
“implemented controller code” I don’t really understand what you are talking about (

None of these examples work.

Please elaborate on what you tried exactly and explain how it failed. We cannot help you with the level of details you shared.

3 Likes