Getting a list of a specific data

Hello, I’m pretty new at working with mongoDB. I’m using it as my database in a small javascript project. I’m looking for a solution to something I’d like to do.

I have a cluster full of userdata, with several properties in each. What would be the best way to retrieve (preferably as an array?) every “id” (not _id) field content, but only where “propertyA” is bigger than “propertyB”. These two properties are both stored as numbers, of course. I’d like to have a list of their id so I can perform an action on all of them in my software, namely to increment propertyB by a number.

If this is something not possible or too complex, getting an array list of EVERY “id” property would be useful aswell.

Thanks in advance!

Hello @Lord_Wasabi, here are couple of ways to get the list of id values as an array from your collection based upon the condition:

var idObjArr = db.collection.find( { $expr: { $gt: [ "$propB", "$propA" ] } }, { _id: 0, id: 1 } ).toArray()
var idArr = []
idObjArr.forEach(doc => idArr.push(doc.id))

Or, you can use this approach; this one only retruns distinct (unique) id values.

var idArr = db.collection.distinct("id", { $expr: { $gt: [ "$propB", "$propA" ] } } )

Hello, thank you for your answer. I tried using your solution like this:

  let idObjArr = client.db.userdata.find( { $expr: { $gt: [ "$currentHP", "$maxHP" ] } }, { _id: 0, id: 1 } )
  let idArr = []
  idObjArr.forEach(doc => idArr.push(doc.id))
  message.channel.send(idArr);

However I’m getting an “Cannot send empty message” here, when trying to print out the array. Seems like nothing is being collected?

I accessed my database like how I usually do. “currentHP” and “maxHP” are the properties. Let me know if I missed something!

Please do a console.log(idArr) after the statement idObjArr.forEach(doc => idArr.push(doc.id)) and see what is there in the array.

Also, you can check if any documents are returned from the query itself:

let count = client.db.userdata.find( { $expr: { $gt: [ "$currentHP", "$maxHP" ] } }, { _id: 0, id: 1 } ).count()
console.log("Count: ", count);

The first one returns [ ], aka an empty array and the count one returns 0

That means there are no matching documents, hence the count zero. The query is correct, for example you can try this in the mongo shell:

Take a test collection with two documents:

{ id: 1, currentHP: 100, maxHP: 200 },
{ id: 2, currentHP: 130, maxHP: 45 }

And the code:

let objs = db.test.find( { $expr: { $gt: [ "$currentHP", "$maxHP" ] } }, { _id: 0, id: 1 } )
let idArr = []
objs.forEach(doc => idArr.push(doc.id))
printjson(idArr)    // this returns [ 2 ]

That shouldn’t be the case, as for example my document already should meet the requirements of the query. Probably should have mentioned that these properties are nested, not sure if it matters

image

(At the bottom)

It does meet the query filter requirement. But, the two fields are in an embedded document stats. So, you need to refer to the two fields as follows in your query (I omitted the remaining parts of the query for brevity):

{ $gt: [ "$stats.currentHP", "$stats.maxHP" ] }

The code below still returns an empty array and count 0, unfortunately

  let idObjArr = await client.db.userdata.find( { $expr: { $gt: [ "$stats.currentHP", "$stats.maxHP" ] } }, { 
  _id: 0, id: 1 } )
  let idArr = []
  idObjArr.forEach(doc => idArr.push(doc.id))
  console.log(idArr)

What are the input documents you are working with? Can you sample couple of them?

The picture above is an example. The project is related to a Discord server, people are saved to the database by their Discord ID (“id” field) and have several properties attached to them. Not everyone has the “CurrentHP” and “MaxHP” properties, but most of them do and everyone who does, has it in the format seen on the picture above. There are other properties in the “stats” object too

In the image the currentHP (100) is less than the maxHP (109) - so it will not select the document. The document will get selected when the currentHP is greater then the maxHP. For example, in the following two documents only the document with id: 2 will be selected:

{ id: 1, stats: { currentHP: 100, maxHP: 200 } },
{ id: 2, stats: { currentHP: 130, maxHP: 45 } }

I see, I probably explained it badly, however the opposite is what I’m trying to achieve. I am trying to get every document’s “id” property, where currentHP < maxHP

I tried switching the two property values in the query around, but that still resulted in an empty array.

You can use the following filter with the $lt (less than comparison operator):

{ $lt: [ "$stats.currentHP", "$stats.maxHP" ] }

The code below still returns an empty array. I seriously feel like I’m missing something here, lol

client.db.userdata.find( { $expr: { $lt: [ "$stats.currentHP", "$stats.maxHP" ] } }, { _id: 0, id: 1 } )

May be. I see you are using the MongoDB NodeJS driver to work with he database data. Can you write a query to count he number of documents in the collection and tell me about the result.

The code below returns 202

client.db.userdata.find( { } ).count()

@Lord_Wasabi, then the filter should work with the sample document in the image you had attached in the earlier comment:

{ $expr: { $lt: [ "$stats.currentHP", "$stats.maxHP" ] } }

image

But it does not :frowning: Here is everything I have:

My full document:

image

My code:

  let idObjArr = client.db.userdata.find( { $expr: { $lt: [ "$stats.currentHP", "$stats.maxHP" ] } }, { _id: 0, 
  id: 1 } )
  let idArr = []
  idObjArr.forEach(doc => idArr.push(doc.id))
  console.log(idArr)

My results:

image

The results when I’m looking up every document in the cluster:

image

See the following documents with examples from MongoDB NodeJS Driver manual if you are writing the code properly: