mongodb - how to get limited number of items from array - reactjs

is it possible somehow to get limited number of items from array?
For now I just can get whoole users data, but I want to have a pagination, where I can load limited number of tasks from users data
async getUserTasks( _id, _limit ) {
try {
await UserModel.find( {
_id: _id,
"tasks": { $size: _limit }
} );
} catch ( e ) {
console.log( e );
}
}
enter image description here

Use limit to cap the number of documents that can be returned from a read operation. limit functions as a cap on the maximum number of documents that the operation can return, but the operation can return a smaller number of documents if there are not enough documents present to reach the limit. If limit is used with the skip method, the skip applies first and the limit only applies to the documents left over after the skip.
Follow the instructions in the examples below to insert data into a collection and return only certain results from a query using a sort, a skip, and a limit. Consider the following collection of documents that describe books:
[
{ "_id": 1, "name": "The Brothers Karamazov", "author": "Dostoyevsky", "length": 824 },
{ "_id": 2, "name": "Les Misérables", "author": "Hugo", "length": 1462 },
{ "_id": 3, "name": "Atlas Shrugged", "author": "Rand", "length": 1088 },
{ "_id": 4, "name": "Infinite Jest", "author": "Wallace", "length": 1104 },
{ "_id": 5, "name": "Cryptonomicon", "author": "Stephenson", "length": 918 },
{ "_id": 6, "name": "A Dance With Dragons", "author": "Tolkein", "length": 1104 },
]
Limit
The following example queries the collection to return the top three longest books. It matches all the documents with the query, applies a sort on the length field to return books with longer lengths before books, and applies a limit to return only 3 results:
// define an empty query document
const query = {};
// sort in descending (-1) order by length
const cursor = collection.find(query).sort({ length: -1 }).limit(3);
await cursor.forEach(console.dir);
The code example above outputs the following three documents, sorted by length:
{ "_id": 2, "title": "Les Misérables", "author": "Hugo", "length": 1462 }
{ "_id": 6, "title": "A Dance With Dragons", "author": "Martin", "length": 1104 }
{ "_id": 4, "title": "Infinite Jest", "author": "Wallace", "length": 1104 }

Related

How to access nested array of objects in mongodb aggregation pipeline?

I have a document like this(this is the result after few pipeline stages)
[
{
"_id": ObjectId("5e9d5785e4c8343bb2b455cc"),
"name": "Jenny Adams",
"report": [
{ "category":"Beauty", "status":"submitted", "submitted_on": [{"_id": "xyz", "timestamp":"2022-02-23T06:10:05.832+00:00"}, {"_id": "abc", "timestamp":"2021-03-23T06:10:05.832+00:00"}] },
{ "category":"Kitchen", "status":"submitted", "submitted_on": [{"_id": "mnp", "timestamp":"2022-05-08T06:10:06.432+00:00"}] }
]
},
{
"_id": ObjectId("5e9d5785e4c8343bb2b455db"),
"name": "Mathew Smith",
"report": [
{ "category":"Household", "status":"submitted", "submitted_on": [{"_id": "123", "timestamp":"2022-02-23T06:10:05.832+00:00"}, {"_id": "345", "timestamp":"2021-03-23T06:10:05.832+00:00"}] },
{ "category":"Garden", "status":"submitted", "submitted_on": [{"_id": "567", "timestamp":"2022-05-08T06:10:06.432+00:00"}] },
{ "category":"BakingNeeds", "status":"submitted", "submitted_on": [{"_id": "891", "timestamp":"2022-05-08T06:10:06.432+00:00"}] }
]
}
]
I have user input for time period -
from - 2021-02-23T06:10:05.832+00:00
to - 2022-02-23T06:10:05.832+00:00
Now I wanted to filter the objects from the report which lie in a certain range of time, I want to only keep the object if the "submitted_on[-1]["timestamp"]" is in range of from and to date timestamp.
I am struggling with accessing the timestamp because of the nesting
I tried this
$project: {
"name": 1,
"report": {
"category": 1,
"status": 1,
"submitted_on": 1,
"timestamp": {
$arrayElemAt: ["$report.cataloger_submitted_on", -1]
}
}
}
But this gets the last object of the report array {"_id": "bcd", "timestamp":"2022-05-08T06:10:06.432+00:00"} for all the items inside the report. How can I do this to select the last timestamp of each obj.
You can replace your phase in the aggregation pipeline with two phases: $unwind and $addFields in order to get what I think you want:
{
$unwind: "$report"
},
{
"$addFields": {
"timestamp": {
$arrayElemAt: [
"$report.submitted_on",
-1
]
}
}
},
The $unwind phase is breaking the external array into documents since you want to perform an action on each one of them. See the playground here with your example. If you plan to continue the aggregation pipeline with more steps, you can probably skip the $addFields phase and include the condition inside your next $match phase.

How to aggregate a MongoDB query to remove the usage of a for loop?

I am new to MongoDB and am working with it on NodeJS code.
As you can see the below code, I am running a for loop through my books collection to figure out the latest version of the query_book.
I know that this isn't efficient, and want to understand how can an aggregation function be written for it in MongoDB.
Current code:
let result= {};
_.forEach(books, function(query_book)
{
if(!result[query_book.book_id])
{
result[query_book.book_id] = query_book
}
else if(result[query_book.book_id].book_version <
query_book.book_version)
{
result[query_book.book_id] = query_book
}
Data Object for books:
[
{
"book_id": "ab12nld”,
"book_version": "0”,
"author": “Sam”,
“name”: “Sample Book”,
“comments”: “Done”
},
{
"book_id": "ab12nld”,
"book_version": "1",
"author": "Martin",
"name": "Sample Book",
“comments”: “In Progress”
},
{
"book_id": "ab12nld”,
"book_version": "2",
"author": "Roy",
"name": "Sample Book",
“comments”: “To-Do”
}
]
[
{
"book_id": "bcj123n”,
"book_version": "0”,
"author": “Don”,
“name”: “Another Book”,
“comments”: “Done”
},
{
"book_id": "bcj123n”,
"book_version": "1",
"author": "Ray",
"name": "Another Book",
“comments”: “In Progress”
},
{
"book_id": "bcj123n”,
"book_version": "2",
"author": "Max",
"name": "Another Book",
“comments”: “To-Do”
}
]
In this case, I want to fetch the object having the maximum value of book_version for my input book_id which is ab12nld:
{
"book_id": "ab12nld”,
"book_version": "2",
"author": "Roy",
"name": "Sample Book",
“comments”: “To-Do”
}
If using Node.js Mongo driver (replace [bookId] with your input)
db.collection('books')
.findOne({ book_id: [bookId] }, { sort: [['book_version', -1]] })
Or, if using Mongoose,
Book.findOne({ book_id: [bookId] }).sort({ book_version: -1 })
db.books.aggregate([{ "$sort": { "book_version": -1 } },{"$limit":1}])
I understood that you want to retrieve a document having highest value of a field.
Here, the document having the highest value in the version field. The simplest way of doing this is to sort in reverse order and get the first document.
You can also use the aggregate method.
Try the following snippet. I think it will help.
db.books.find().sort({"book_version":-1}).limit(1);

How to update object fields inside nested array and dynamically set a field value based on some inputs

I have been working on a Mongo database for a while. The database has some visits that have this form:
[
{
"isPaid": false,
"_id": "5c12bc3dcea46f9d3658ca98",
"clientId": "5c117f2d1d6b9f9182182ae4",
"came_by": "Twitter Ad",
"reason": "Some reason",
"doctor_services": "Some service",
"doctor": "Dr. Michael",
"service": "Special service",
"payments": [
{
"date": "2018-12-13T21:23:05.424Z",
"_id": "5c12cdb9b236c59e75fe8190",
"sum": 345,
"currency": "$",
"note": "First Payment"
},
{
"date": "2018-12-13T21:23:07.954Z",
"_id": "5c12cdbbb236c59e75fe8191",
"sum": 100,
"currency": "$",
"note": "Second payment"
},
{
"date": "2018-12-13T21:23:16.767Z",
"_id": "5c12cdc4b236c59e75fe8192",
"sum": 5,
"currency": "$",
"note": "Third Payment"
}
],
"price": 500,
"createdAt": "2018-12-13T20:08:29.425Z",
"updatedAt": "2018-12-13T21:42:21.559Z",
}
]
I need to find some query to update some field of a single payment based on the _id of the visit and _id of the payment that is inside of nested array. Also when you update a payment's sum to some number so that the sum of all payments is greater than or equal to price the field isPaid is automatically updated to true.
I have tried some queries in mongoose to achieve the first part but none of them seem to work:
let paymentId = req.params.paymentId;
let updatedFields = req.body;
Visit.update(
{ "payments._id": paymentId },
{
$set: {
"visits.$": updatedFields
}
}
).exec((err, visit) => {
if (err) {
return res.status(500).send("Couldn't update payment");
}
return res.status(200).send("Updated payment");
});
As for the second part of the question I haven't really come up with anything so I would appreciate at least giving some direction on how to approach it.

Retrieve faceted results with non default count value(10) from Azure Search

I am using the Azure index for an index search. My objective behind the Index search is to retrieve the Unique records depend upon some unique parameter say System_ID and I started using facets feature for this, but when using it I am unable to retrieve more than 10 unique facets despite providing a count value to 20 in the query.
Below is the summary:
I am able to retrieve only 10 unique records even though more than 10 unique records are there in Index.
When i modify the count property of facet to 20 Still I am getting only 10 records
Can you please help with me to modify it in such a way that I will get more than 10 records.
Any help will be appreciable.
Default query:
$filter=(systemID ne null) and (ownerSalesforceRecordID eq 'a0h5B000000gJKfQAM')&facet=machineTagSystemID,sort:value&queryType=full
Default Results:
{"machineTagSystemID": [
{
"count": 9,
"value": "ABCS test machines-111-test - change|*1XA78RUGV23PVPN"
},
{
"count": 6,
"value": "Ajit Machine testing1jjcdxxxxxxxxxxxxxx|*1L693D439H5ZNG9"
},
{
"count": 19,
"value": "Anvesh test111dsaa|*13SSNP5AJ3L96C5"
},
{
"count": 3,
"value": "Dead End cross 2|*1NK7KNNLFVTM4QC"
},
{
"count": 3,
"value": "hehehe|*1NDC32TDNXT5RAH"
},
{
"count": 14,
"value": "high2 Machine12345678ppjk fvrf|*1T2F3VQEJ58ZLQL"
},
{
"count": 31,
"value": "prashant dev machine 213|*12L343TZTFGH3M6"
},
{
"count": 1,
"value": "ryansjcilaptop465986543|*1E2PG9V3BMEYDM7"
},
{
"count": 12,
"value": "snehali DEV June|*1QXEDL8E2V8MGBY"
},
{
"count": 27,
"value": "tarun Machine-dev|*1YRPHS3J7NGUVA8"
}
]}
Facet with count:
$filter=(systemID ne null) and (ownerSalesforceRecordID eq 'a0h5B000000gJKfQAM')&facet=machineTagSystemID,sort:value,count:20&queryType=full
But same results:
{"machineTagSystemID": [
{
"count": 9,
"value": "ABCS test machines-111-test - change|*1XA78RUGV23PVPN"
},
{
"count": 6,
"value": "Ajit Machine testing1jjcdxxxxxxxxxxxxxx|*1L693D439H5ZNG9"
},
{
"count": 19,
"value": "Anvesh test111dsaa|*13SSNP5AJ3L96C5"
},
{
"count": 3,
"value": "Dead End cross 2|*1NK7KNNLFVTM4QC"
},
{
"count": 3,
"value": "hehehe|*1NDC32TDNXT5RAH"
},
{
"count": 14,
"value": "high2 Machine12345678ppjk fvrf|*1T2F3VQEJ58ZLQL"
},
{
"count": 30,
"value": "prashant dev machine 213|*12L343TZTFGH3M6"
},
{
"count": 1,
"value": "ryansjcilaptop465986543|*1E2PG9V3BMEYDM7"
},
{
"count": 12,
"value": "snehali DEV June|*1QXEDL8E2V8MGBY"
},
{
"count": 27,
"value": "tarun Machine-dev|*1YRPHS3J7NGUVA8"
}
]}
This is based on the documentation link: https://learn.microsoft.com/en-us/azure/search/search-faceted-navigation
Facets honor the filter specified in a query. It's possible this is why you are only seeing 10 unique facet value for this field. Generally speaking, your query looks fine. If there were more than 10 unique values in this field for the query specified, I would expect them to show up.
How many total results are returned by this query? I see 125 total values in the facets you provided and I'm wondering if the count aligns with your results.
Mike
This is old but I hit the same issue - there is a default limit of 10 values returned in a facet, you can extend this to return more facet values by adding a count to a given facet. E.g.:
facet=Month,count:12&search=something
This can also be done in the c# API by just adding the count to the facet name:
var options = new SearchOptions();
options.Facets.Add("Month,count:12");

moongoose query array of objects of array using lodash or underscorejs

Here is an example of my data:
[
{
"_id": "54ff1f21592a15378825aa33",
"timeline": "54fb49274e3e0c17271205d9",
"name": "Ade Idowu",
"first_name": "Ade",
"last_name": "Idowu",
"cohort": {
"name": "Class III",
"color": "#308cea"
},
"__v": 3,
"tasks": [
{
"_id": "54ff2eb0a6299969a08f8797",
"personName": "Ade Idowu",
"projectName": "yec",
"startDate": "2015-03-19T23:00:00.000Z",
"endDate": "2015-03-06T23:00:00.000Z",
}
]
},
{
"_id": "54ff1f21592a15378825aa33",
"timeline": "54fb49274e3e0c17271205d9",
"name": "Bola Idowu",
"first_name": "Bola",
"last_name": "Idowu",
"cohort": {
"name": "Class III",
"color": "#308cea"
},
"__v": 3,
"tasks": []
}
]
I want to query person.tasks to display names of those whose tasks array is empty and those whose tasks.endDate has expired. I would appreciate using javascript or probably lodash.
Use lodash _.filter(collection, predicate):
Iterates over elements of collection, returning an array of all
elements predicate returns truthy for.
Predicate checks if iteree's task array is empty or the task endDate is smaller then the current time.
.getTime() returns the ms value of the date object so you can compare the two dates. This could be adjusted if you would like to filter by another granularity (ex. hours, days).
_.filter(dataObject, function(item){
var now = new Date();
return item.tasks.length == 0 || (newDate(item.tasks.endDate).getTime() < now.getTime());
});

Resources