How to sort in a specific order of a key in MongoDB - mongodb

Good day. I have the following documents.
{
id: 1,
status: "sleeping"
}
{
id: 2,
status: "eating"
},
{
id: 3,
status: "drinking"
},
{
id: 4,
status: "drinking"
},
{
id: 5,
status: "sleeping"
},
{
id: 6,
status: "studying"
},
...
How do I sort them by status with the following order? sleeping, drinking, eating, studying
I'm using Angular-Meteor. And I'm trying to publish a collection with a limit in the server since I'm dealing with a very large data set.
I was looking into aggregate which I think is the right solution for this case but Meteor doesn't support it.

Well, I ended up with attaching a number to sort the the documents in the following order: sleeping, drinking, eating, studying
{
id: 1,
status: "sleeping",
statusOrder: 0
}
{
id: 2,
status: "eating",
statusOrder: 2
},
{
id: 3,
status: "drinking",
statusOrder: 1
},
{
id: 4,
status: "drinking",
statusOrder: 1
},
{
id: 5,
status: "sleeping",
statusOrder: 0
},
{
id: 6,
status: "studying",
statusOrder: 3
},
...
It was easier, quite frankly.
But if you are interested with using MongoDB group for your app, I found something that might help. Link here.

The mongodb aggregation framework is available on the server side via the monbro:mongodb-mapreduce-aggregation package (for example). You can use this in your publication.
Another approach is to denormalize your data somewhat and include the sort key in each document. That involves a typical storage vs. speed tradeoff.

MongoDb just only support sort following A -> Z, Z -> A, 0 -> 9, 9 -> 0
Specify in the sort parameter the field or fields to sort by and a value of 1 or -1 to specify an ascending or descending sort respectively.
Example:
db.orders.find().sort( { "status": -1 } )

Related

What is the mongo compound index keyword arrangement rule? Numbers first, strings later?

When I used numbers as keys, the compound index prefixes created were not as expected。
To define a compound index:
admin> use TestDB
TestDB> db.createCollection('coll')
TestDB> db.coll.createIndex({4:1,1:-1},{unique:true})
TestDB> db.coll.getIndexex()
Output
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{ v: 2, key: { '1': -1, '4': 1 }, name: '1_-1_4_1', unique: true }
]
I expected 4 to be the prefix of the index, but it turned out to be 1, why?
It looks like the sorting happens
And when I use strings as keywords, the results are completely inconsistent。
Following:
TestDB> db.createCollection("coll2")
TestDB> db.coll2.createIndex({'s':1, 'a':-1},{unique:true})
Output
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{ v: 2, key: { s: 1, a: -1 }, name: 's_1_a_-1', unique: true }
]
What? It doesn't seem to be sorting.
According to this issue, which references the official specification, this is a result of how Javascript works.
For example, in Node:
$ node
Welcome to Node.js v16.17.0.
Type ".help" for more information.
> var pattern = { 4: 1, 1: -1 }
undefined
> pattern
{ '1': -1, '4': 1 }
You can see similar behavior in this jsfiddle.
If you are attempting to create indexes that have numeric keys, you will need to do so with a different language/driver.

Updating multiple items in nested array when condition matched

I started learning MongoDB a few days ago and trying to wrap my head around update operator.
Here's the document structure I have:
db.records.insertMany([
{
name: 'first',
subrecords: [
{ id: 1, isToBeUpdated: 0, value: 1 },
{ id: 2, isToBeUpdated: 0, value: 2 },
{ id: 3, isToBeUpdated: 0, value: 3 },
{ id: 4, isToBeUpdated: 1, value: 4 }
]
},
{
name: 'second',
subrecords: [
{ id: 22, isToBeUpdated: 1, value: 5 },
{ id: 23, isToBeUpdated: 0, value: 6 },
{ id: 24, isToBeUpdated: 1, value: 7 },
{ id: 25, isToBeUpdated: 0, value: 8 }
]
}
])
I'm writing a command that is supposed to update subrecords.
My intent is to use isToBeUpdated flag — if it is set to 1 we update the value field, e.g. multiplying it by 10. We ignore items with isToBeUpdated being 0.
Here's the command I've composed:
db.records.update(
{ 'subrecords.isToBeUpdated': 1 },
{ '$mul': { 'subrecords.$.value': 10 } },
{ multi: true }
)
I expect to get the following items of subrecords array updated like this:
1. { id: 4, isToBeUpdated: 1, value: 40 }
2. { id: 22, isToBeUpdated: 1, value: 50 }
3. { id: 24, isToBeUpdated: 1, value: 70 }
BUT it just updates 2 records, instead of 3. The following record is not updated:
3. { id: 24, isToBeUpdated: 1, value: 70 }
It is the second item with isToBeUpdated being 1 located in the second document's subrecords collection — seems like the query only updates the first matching item of subrecords array in any document. And ignores other records that are subsequent to first.
I tried tweaking my command adding [] to $ (positional operator):
... { '$mul': { 'subrecords.$[].value': 10 } }, ...
But in this case literally every single item in subrecords array of any document gets affected.
Anyone knows how to write a command which loops through all records and updates each item of the nested subrecords array with isToBeUpdated field being set to 1?
Also, am I right in thinking
that { multi: true } implies that ALL record documents in records collection will be affected?
that { 'subrecords.isToBeUpdated': 1 } (query part) literally means that WE ONLY UPDATE subrecords ARRAY WHEN A DOCUMENT HAS AT LEAST ONE ITEM IN subrecords ARRAY WITH isToBeUpdated FIELD BEING SET TO 1?
The workaround turns out to be arrayFilters
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#update-all-documents-that-match-arrayfilters-in-an-array
The $[<identifier>] operator facilitates updates to arrays that contain embedded documents. To access the fields in the embedded documents, use the dot notation on the $[<identifier>].
db.records.update(
{},
{ '$mul': { 'subrecords.$[elem].value': 10 } },
{
multi: true,
arrayFilters: [{ 'elem.isToBeUpdated': 1 }]
}
)
Solved!

MongoDB - distinct with query doesn't use indexes

Using Mongo 3.2.
Let's say I have a collection with this schema:
{ _id: 1, type: a, source: x },
{ _id: 2, type: a, source: y },
{ _id: 3, type: b, source: x },
{ _id: 4, type: b, source: y }
Of course that my db is much larger and with many more types and sources.
I have created 4 indexes combinations of type and source (even though 1 should be enough):
{type: 1}
{source: 1},
{type: 1, source: 1},
{source: 1, type: 1}
Now, I am running this distinct query:
db.test.distinct("source", {type: "a"})
The problem is that this query takes much more time that it should take.
If I run it with runCommand:
db.runCommand({distinct: 'test', key: "source", query: {type: "a"}})
this is the result i get:
{
"waitedMS": 0,
"values": [
"x",
"y"
],
"stats": {
"n": 19400840,
"nscanned": 19400840,
"nscannedObjects": 19400840,
"timems": 14821,
"planSummary": "IXSCAN { type: 1 }"
},
"ok": 1
}
For some reason, mongo use only the type: 1 index for the query stage.
It should use the index also for the distinct stage.
Why is that? Using the {type: 1, source: 1} index would be much better, no? right now it is scanning all the type: a documents while it has an index for it.
Am I doing something wrong? Do I have a better option for this kind of distinct?
As Alex mentioned, apparently MongoDB doesn't support this right now.
There is an open issue for it:
https://jira.mongodb.org/browse/SERVER-19507
Just drop first 2 indexes. You don't need them. Mongo can use {type: 1, source: 1} in any query that may need {type: 1} index.

MongoDB update outter and array-embedded document atomically

I have an object in the cart collection:
{
_id: 1,
purchased: 0,
items: [
{
item_id: 5,
count: 0
},
{
item_id: 6,
count: 0
},
]
}
And I would like to atomically increment both purchased and count of item_id: 6. I believe the correct update command is:
db.carts.update({_id: 1, "items.item_id": 6},
{
$inc: {
purchased: 1
"items.$.count": 1
}
})
This seems to work in the console but I am not sure if this is 100% correct. Can anyone spot any issues with this update command or confirm this is correct for my use case?
For scaling this to my app, suppose _id is an ObjectId and item_id is also ObjectId (ie they are unique).

updated array of objects sailsjs

In my mongodb had collections Category as: [{catid: 1, id:1 }, {catid:1, id:2 },{catid:1, id: 3},{catid:1, id:4},{catid:2}]
How to using update method as: Category.update({catid:1}, [{catid:1, status:'sick'},{catid:1, status:'angry'},{catid: 1, status: 'boring'}, {catid: 1, status: 'happy'}]).exec(function(Err, updated){})
thanks all!