RethinkDB pagination using slice or limit & skip with changes() - pagination

How can i do pagination in RethinkDB with changes()?
None of these options does not work:
r.db('bustest').table('client').orderBy({index: r.desc("id")}).slice(3, 3).changes()
r.db('bustest').table('client').orderBy({index: r.desc("id")}).skip(3).limit(3).changes()
Only it works:
r.db('bustest').table('client').orderBy({index: r.desc("id")}).limit(3).changes()
UPDATE:
For example, skip after changes():
r.db('bustest').table('client').orderBy({index: r.desc("id")}).limit(3).changes({squash: 0.05, includeInitial: true, includeStates: true})
return:
{
"state": "ready"
},
{
"new_val": {
"first_name": "Gruzin" ,
"id": "e9580339-b908-4349-a208-c3d1e25bf7ba" ,
"last_name": "Bagal"
}
},
{
"new_val": {
"first_name": "e31db5422cd74040" ,
"id": "efadedd0-56f2-498f-ad04-5191e2be1244" ,
"last_name": "27d6b3a140235275"
}
},
{
"new_val": {
"first_name": "2ba4a9d0e3616865" ,
"id": "f5c7f3b7-23d2-4661-a5b7-91b977635556" ,
"last_name": "b7f4df90a27bb05b"
}
},
{
"state": "initializing"
}
And with skip:
r.db('bustest').table('client').orderBy({index: r.desc("id")}).limit(3).changes({squash: 0.05, includeInitial: true, includeStates: true}).skip(3)
return:
{
"state": "ready"
},
{
"new_val": {
"first_name": "Gruzin" ,
"id": "e9580339-b908-4349-a208-c3d1e25bf7ba" ,
"last_name": "Bagal"
}
}
Skip after changes() didn't work. But pagination with changes() is very important part for my projects.

That's what is documented on https://rethinkdb.com/docs/changefeeds/ruby/#filtering-and-aggregation
You cannot use them with slice skip. Only orderBy, and follow by limit. Only orderBy before changes also works
To paginate the changes itself, (mean data return by change feed), after changes(), you can call skip, and just iterator the return cursor yourself. However, if you use limit or slice after changes, the changefeeds only return that amount of change, and close changefeed.

Related

Remove object from nested array in MongoDB using NodeJS

I can see that this question should have been answered here, but the code simply doesn't work for me (I have tried multiple, similar variations).
Here is my data:
[{
"_id": {
"$oid": "628cadf43a2fd997be8ce242"
},
"dcm": 2,
"status": true,
"comments": [
{
"id": 289733,
"dcm": 2,
"status": true,
"clock": "158",
"user": "Nathan Field",
"dept": "IT",
"department": [],
"dueback": "",
"comment": "test 1"
},
{
"id": 289733,
"dcm": 2,
"status": true,
"clock": "158",
"user": "Nathan Field",
"dept": "IT",
"department": [],
"dueback": "",
"comment": "test 2"
}
],
"department": [],
"dueback": ""
}]
And here is my code
const deleteResult = await db.collection('status').updateOne(
{ "dcm": comments.dcm },
{ $pull: { "comments": { "id": comments.id } } },
{ upsert: false },
{ multi: true }
);
Absolutely nothing happens...
So the issue ended up being something to do with running multiple update operations within one function. I have a database connection function like this:
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('collection');
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error });
}
}
And then I call this by using:
withDB(async (db) => {
await db.collection('status').updateMany(
{ "dcm": comments.dcm },
{ $pull: { "comments": { "id": comments.id } } },
{ multi: true }
);
});
The issue occurred it would seem because I had two of these update operations within one withDB function. I have multiple operations in other instances (update item, then fetch collection), but for some reason this caused an issue.
I created a separate call to the withDB function to perform the '$pull' (delete) request, and then updated the array with the new comments.
To check that there was nothing wrong with my actual query, I used Studio3T's IntelliShell feature. If I'd done that sooner I would saved myself a lot of time!

Not able to query for nested relations using dgraph-orm

I am using dgraph-orm for fetching nested relational values but it works for single level but not multiple level.
I am getting the page details but unable to fetch the avatar of the page.
Here is my snippet:
let posts = await PagePost.has('page_id', {
filter: {
page_id: {
uid_in: [page_id]
}
},
include: {
page_id: {
as: 'page',
include: {
avatar: {
as: 'avatar'
}
}
},
owner_id: {
as: 'postedBy'
}
},
order: [], // accepts order like the above example
first: perPage, // accepts first
offset: offset, // accepts offset
});
I am not getting avatar for the attribute page_id:
{
"uid": "0x75b4",
"title": "",
"content": "haha",
"created_at": "2019-09-23T08:50:52.957Z",
"status": true,
"page": [
{
"uid": "0x75ac",
"name": "Saregamaapaaaa...",
"description": "This a is place where you can listen ti thrilling music.",
"created_at": "2019-09-23T06:46:50.756Z",
"status": true
}
],
"postedBy": [
{
"uid": "0x3",
"first_name": "Mohit",
"last_name": "Talwar",
"created_at": "2019-07-11T11:37:33.853Z",
"status": true
}
]
}
Is there a support for multilevel field querying in the orm??
There was some issue with ORM itself it was not able to recognize the correct model name for multilevel includes and generating the wrong queries.
Fixed the same in version 1.2.4, please run npm update dgraph-orm --save to update your DgraphORM.
Thanks for the issue.

Update whole child element of an array field of an document in mongodb nodejs

Considering the following document, i want to update whole field of dataset with _id:123,
"data": {
"_id": "1234546",
"dataset": [
{
"_id": "123",
"el2": "asd",
"el3": "sd",
"el4": "gfdd",
"el5": "asdfa",
},
{
"_id": "787",
"el2": "asd",
"el3": "sd",
"el4": "gfdd",
"el5": "asdfa",
},
{
"_id": "898",
"el2": "asd",
"el3": "sd",
"el4": "gfdd",
"el5": "asdfa",
},
{
"_id": "564",
"el2": "asd",
"el3": "sd",
"el4": "gfdd",
"el5": "asdfa",
},
]
}
I want to update all fields of an array element by using _id of field.
I am using
getDB.collection ('data').findOneAndUpdate(
{ _id: new ObjectId(data.userId),
"dataset._id":new ObjectId(data.dataset),
},
{ $set: { "userAddress.$":newdataset } },
{returnOriginal:false}});
Please suggest some good option to update it.
Thanks in advance.. :)
If you want to just update the document on the db server without fetching it, you could use update instead of findOneAndUpdate.
Here a way to do it.
collection('data').update({
_id:<_id>,
"dataset._id":<dataset._id>
},{
$set:{
"dataset.$.el2":<el2>,
"dataset.$.el3":<el3>,
"dataset.$.el4":<el4>,
"dataset.$.el5":<el5>
}
})

Node + Mongodb. $pull not working?

I am using Node.js and MongoDB and I'm trying to setup a DELETE route. In the function responsible for handling the delete I am using Mongo's "$pull" operator. I've looked at a couple of examples now and I don't know what I am doing wrong.
Here's a sample of how the database documents are setup
{
"_id": {
"$oid": "123abc"
},
"sleepData": [
{
"date": "03/28/2016",
"hour": "11",
"minute": "11",
"meridiem": "PM",
"feeling": "7"
},
{
"date": "03/29/2016",
"hour": "3",
"minute": "41",
"meridiem": "PM",
"feeling": "1"
},
{
"date": "03/30/2016",
"hour": "1",
"minute": "29",
"meridiem": "AM",
"feeling": "5"
},
{
"date": "03/30/2016",
"hour": "1",
"minute": "38",
"meridiem": "AM",
"feeling": "4"
},
]
}
*Note the near-duplicate data, thus the reason why my $pull query is so specific.
Here is my function for the route
module.exports.DELETE = function(req, res) {
var sleepDataToDelete = {
date: req.query.date,
hour: req.query.hour,
minute: req.query.minute,
meridiem: req.query.meridiem,
feeling: req.query.feeling
};
// next code block is what this console prints out
console.log("Deleting req.query:\n", sleepDataToDelete);
var sleepObjectId = req.query.sleepObjectId;
var sleepDataCollection = db.get().collection('sleepData');
sleepDataCollection.update(
{
_id: sleepObjectId
},
{
$pull: {
sleepData: {
date: sleepDataToDelete.date,
hour: sleepDataToDelete.hour,
minute: sleepDataToDelete.minute,
meridiem: sleepDataToDelete.meridiem,
feeling: sleepDataToDelete.feeling
}
}
},
function(err, result) {
if(err) {
console.log("err", err);
return res.status(400).end();
} else {
console.log("Count: ", result.result.n);
console.log("Deleted! :) ");
return res.status(200).end();
}
}
);
};
This is what the console.log("Deleting req.query:\n", sleepDataToDelete); prints out, which also matches the third index in the sleepData array.
Deleting req.query:
{
date: '03/30/2016',
hour: '1',
minute: '29',
meridiem: 'AM',
feeling: '5'
}
I have even tried putting the json field names in double/single quotes, but that didn't work either. The number of objects modified is 0. I have also tried reducing the "$pull {...}" query to just "date" instead of having "date", "hour", "minute", "meridiem", and "feeling." This still results in 0 modified items from the print statement.
As #BlakesSeven pointed out, I was not passing in an ObjectId in my query. So, credit goes to him. Needless to say, this solved my issue.

MongoDB: Query model and check if document contains object or not, then mark / group result

I have a Model called Post, witch contains an property array with user-ids for users that have liked this post.
Now, i need to query the post model, and mark the returned results with likedBySelf true/false for use in by client - is this possible?
I dont have to store the likedBySelf property in the database, just modify the results to have that property.
A temporary solution i found was to do 2 queries, one that finds the posts that is liked by user x, and the ones that have not been liked by user x, and en map (setting likedBySelf true/false) and combine the 2 arrays and return the combined array. But this gives some limitations to other query functions such as limit and skip.
So now my queries looks like this:
var notLikedByQuery = Post.find({likedBy: {$ne: req.body.user._id}})
var likedByQuery = Post.find({likedBy: req.body.user._id})
(I'm using the Mongoose lib)
PS. A typical post can look like this (JSON):
{
"_id": {
"$oid": "55fc463c83b2d2501f563544"
},
"__t": "Post",
"groupId": {
"$oid": "55fc463c83b2d2501f563545"
},
"inactiveAfter": {
"$date": "2015-09-25T17:13:32.426Z"
},
"imageUrl": "https://hootappprodstorage.blob.core.windows.net/devphotos/55fc463b83b2d2501f563543.jpeg",
"createdBy": {
"$oid": "55c49e2d40b3b5b80cbe9a03"
},
"inactive": false,
"recentComments": [],
"likes": 8,
"likedBy": [
{
"$oid": "558b2ce70553f7e807f636c7"
},
{
"$oid": "559e8573ed7c830c0a677c36"
},
{
"$oid": "559e85bced7c830c0a677c43"
},
{
"$oid": "559e854bed7c830c0a677c32"
},
{
"$oid": "559e85abed7c830c0a677c40"
},
{
"$oid": "55911104be2f86e81d0fb573"
},
{
"$oid": "559e858fed7c830c0a677c3b"
},
{
"$oid": "559e8586ed7c830c0a677c3a"
}
],
"location": {
"type": "Point",
"coordinates": [
10.01941398718396,
60.96738099591897
]
},
"updatedAt": {
"$date": "2015-09-22T08:45:41.480Z"
},
"createdAt": {
"$date": "2015-09-18T17:13:32.426Z"
},
"__v": 8
}
#tskippe you can use a method like following to process whether the post is liked by the user himself and call the function anywhere you want.
var processIsLiked = function(postId, userId, doc, next){
var q = Post.find({post_id: postId});
q.lean().exec(function(err,res){
if(err) return utils.handleErr(err, res);
else {
if(_.find(doc.post.likedBy,userId)){ //if LikedBy array contains the user
doc.post.isLiked = true;
} else {
doc.post.isLiked = false;
}
});
next(doc);
}
});
}
Because you are using q.lean() you dont need to actually persist the data. You need to just process it , add isLiked field in the post and send back the response. **note that we are manuplating doc directly. Also you chan tweek it to accept doc containing array of posts and iterating it and attach an isLiked field to each post.
I found that MongoDB's aggregation with $project tequnique was my best bet. So i wrote up an aggregation like this.
Explanation:
Since i want to keep the entire document, but $project purpose is to modify the docs, thus you have to specify the properties you want to keep. A simple way of keeping all the properties is to use "$$ROOT".
So i define a $project, set all my original properties to doc: "$$ROOT", then create a new property "likedBySelf", which is marked true / false if a specified USERID is in the $likedBy set.
I think that this is more clean and simple, than querying every single model after a query to set a likedBySelf flag. It may not be faster, but its cleaner.
Model.aggregate([
{ $project: {
doc: "$$ROOT",
likedBySelf: {
$cond: {
"if": { "$setIsSubset": [
[USERID],
"$likedBy"
]},
"then": true,
"else": false
}
}
}}
]);

Resources