I am working on small form in electron and pouchdb.
When inserting a data into db, until the ninth doc it inserting perfectly, but on 10th doc it is inserting to second position of doc instead on inserting into last
before inserting the 10th doc
{
"total_rows": 9,
"offset": 0,
"rows": [
{ "id": "1", "key": "1", "value": {...} },
{ "id": "2", "key": "2", "value": {...} },
{ "id": "3", "key": "3", "value": {...} },
{ "id": "4", "key": "4", "value": {...} }
{ "id": "5", "key": "5", "value": {...} },
{ "id": "6", "key": "6", "value": {...} },
{ "id": "7", "key": "7", "value": {...} },
{ "id": "8", "key": "8", "value": {...} },
{ "id": "9", "key": "9", "value": {...} }
]
}
After inserting 10th doc
{
"total_rows": 10,
"offset": 0,
"rows": [
{ "id": "1", "key": "1", "value": {...} },
{ "id": "10", "key": "10", "value": {...} },
{ "id": "2", "key": "2", "value": {...} },
{ "id": "3", "key": "3", "value": {...} },
{ "id": "4", "key": "4", "value": {...} }
{ "id": "5", "key": "5", "value": {...} },
{ "id": "6", "key": "6", "value": {...} },
{ "id": "7", "key": "7", "value": {...} },
{ "id": "8", "key": "8", "value": {...} },
{ "id": "9", "key": "9", "value": {...} }
]
}
here attached the js code
// form submit
const form = document.getElementById("form1");
form.addEventListener("submit", dbsubmit);
function dbsubmit(e) {
e.preventDefault();
// getting values from form
var Sno = document.getElementById("number").value
var date = document.getElementById("date").value;
var Time = document.getElementById("time").value;
var Trip = document.querySelector('input[name="Trip"]:checked').value;
var TripType = document.querySelector('input[name="Type"]:checked').value;
// assigning form values to db table names
var doc = {
_id: Sno,
Date: date,
time: Time,
trip: Trip,
triptype: TripType,
};
// inserting to db
db.put(doc, function(err, response) {
if (err) {
return console.log(err);
} else {
console.log("Document created Successfully", response);
}
});
}
Inserting until ninth 9th doc it's perfectly inserting but when inserting the 10th doc it is inserting in second position.
The doc should be sorted by id and want to use it to view in another page.
I debugged but cannot find a solution, can anyone help me with the solution?
Thank you
You have an errant notion regarding document insertion, whether as if the order of insertion with respect to time matters which is to be expected from say an RDBMS like MS/SQL, or a belief that a string representation of a numeric value should be sorted according to the implied numerical value (which would be wild guessing by the db).
As explicitly stated here, here and here, and as specified by the CouchDB documentation 3.2.2.5. Collation Specification
Comparison of strings is done using ICU which implements the Unicode Collation Algorithm, giving a dictionary sorting of keys. This can give surprising results if you were expecting ASCII ordering.
Documents are not returned by order of insertion rather they are returned according to the collation rules applied to the document ids, and document ids are strings.
For example you expect this ordering:
row # | id |
---|---|
0 | 1 |
1 | 2 |
2 | 3 |
3 | 4 |
4 | 5 |
5 | 6 |
6 | 7 |
7 | 8 |
8 | 9 |
9 | 10 |
BUT that is not according to the collation rules, which yields
row # | id |
---|---|
0 | 1 |
1 | 10 |
2 | 2 |
3 | 3 |
4 | 4 |
5 | 5 |
6 | 6 |
7 | 7 |
8 | 8 |
9 | 9 |
Again, it cannot be emphasized enough that the order of insertion, much less an implied numeric value, does not affect the order of results. From an RDBMS perspective it is helpful to approach _all_docs results as being ordered by an index on _id
which is sorted according to collation rules (again, for strings since all _id
s are of type string).
The snippet below demonstrates this by creating 100 documents with ids ranging from 1 to 100.
// generate canned test documents with doc _id's in the range 1 to 100.
function getDocsToInstall() {
let docs = [];
for (let i = 1; i < 101; i++) {
// _id must be a string type because that's the way it is, period.
docs.push({
_id: i.toString()
});
}
return docs;
}
let db;
// init db instance
async function initDb() {
db = new PouchDB('test', {
adapter: 'memory'
});
await db.bulkDocs(getDocsToInstall());
}
initDb().then(async() => {
let options = {
limit: 25,
include_docs: false,
reduce: false
};
const result = await db.allDocs(options);
showResult(result);
});
function gel(id) {
return document.getElementById(id);
}
function cel(name) {
return document.createElement(name);
}
function addColumn(tr, value) {
const td = cel('td');
td.innerText = value;
tr.append(td);
}
function addRow(row, index) {
const tr = cel('tr');
[index, row.id].forEach(value => addColumn(tr, value));
gel('table').append(tr);
}
function showResult(result) {
const table = gel('table');
result.rows.forEach((row, index) => {
addRow(row, index);
});
}
th,
td {
padding: .5em;
text-align: left;
min-width: 4em;
}
table {
border-collapse: collapse;
}
<script src="https://cdn.jsdelivr.net/npm/pouchdb@7.1.1/dist/pouchdb.min.js"></script>
<script src="https://github.com/pouchdb/pouchdb/releases/download/7.1.1/pouchdb.memory.min.js"></script>
<table id="table" border="1">
<tr>
<th>row #</th>
<th>id</th>
</tr>
</table>
The must-get takeaway from the snippet is that the first 3 documents returned are
row # | id |
---|---|
0 | 1 |
1 | 10 |
2 | 100 |
As janl pointed out here if you need to access documents in terms of numerical ordering, then creating a view is a good option, which the following snippet demonstrates.
The snippet shows results from _all_docs and the my_index view side by side.
// generate canned test documents with doc _id's in the range 1 to 100.
function getDocsToInstall() {
let docs = [];
for (let i = 1; i < 101; i++) {
// _id must be a string type because that's the way it is, period.
docs.push({
_id: i.toString()
});
}
// add a design doc/view for numerically ordered documents
docs.push({
_id: '_design/my_ddoc',
views: {
my_index: {
map: function(doc) {
emit(Number(doc._id));
}.toString()
}
}
})
return docs;
}
let db;
// init db instance
async function initDb() {
db = new PouchDB('test', {
adapter: 'memory'
});
await db.bulkDocs(getDocsToInstall());
}
initDb().then(async() => {
let options = {
limit: 25,
include_docs: false,
reduce: false
};
const allDocs = await db.allDocs(options);
const view = await db.query('my_ddoc/my_index');
showResult(allDocs, view);
});
function gel(id) {
return document.getElementById(id);
}
function cel(name) {
return document.createElement(name);
}
function addColumn(tr, value) {
const td = cel('td');
td.innerText = value;
tr.append(td);
}
function addRow(index, allDocs, view) {
const tr = cel('tr');
[index, allDocs.rows[index].key, view.rows[index].key].forEach(value => addColumn(tr, value));
gel('table').append(tr);
}
// show allDocs and view results side by side
function showResult(allDocs, view) {
const table = gel('table');
for (let i = 0; i < allDocs.rows.length; i++) {
addRow(i, allDocs, view);
};
}
th,
td {
padding: .5em;
text-align: left;
min-width: 4em;
}
table {
border-collapse: collapse;
}
<script src="https://cdn.jsdelivr.net/npm/pouchdb@7.1.1/dist/pouchdb.min.js"></script>
<script src="https://github.com/pouchdb/pouchdb/releases/download/7.1.1/pouchdb.memory.min.js"></script>
<table id="table" border="1">
<tr>
<th>row #</th>
<th>_all_docs key</th>
<th>my_index key</th>
</tr>
</table>
Note that for _all_docs, key
and id
are the document _id
. It's important to understand that _all_docs is in fact a built-in view which explains why key
and id
are present in _all_docs results.
If in fact you want documents ordered with respect to time, then add a creation timestamp to documents and build a view based on that timestamp, e.g. the map function might look like this if creationTime
is an integer representing a point in time (milliseconds) in the Unix epoch.
function(doc) {
emit(doc.creationTime);
}