groupBy query with nodejs ravendb client - node.js

I am trying to perform groupBy query on ravendb, using nodejs-ravendb-client!
const apmts = await session.query<Appointment>({ collection: "Appointments" })
.statistics(s => (stats = s))
.groupBy("client.name").all();
facing this error on typescript compile
Property 'all' does not exist on type 'IGroupByDocumentQuery<Appointment>'.ts(2339)
Any help here?

Document query's groupBy() method returns an object of type IGroupByDocumentQuery
As you can see it does not have all() method.
You can use selectKey(), selectCount() or selectSum() for aggregation and then chain it with all(). E.g.:
const { GroupByField } = require("ravendb");
const orders = await session.query({ collection: "Orders" })
.groupBy("ShipTo.Country")
.selectKey("ShipTo.Country", "Country")
.selectSum(new GroupByField("Lines[].Quantity", "OrderedQuantity"))
.all();
For more details and examples please refer to official documentation:

Related

Mongoose findOneAndUpdate() using current data

I am try to track the number of downloads per click on a website.
server.js
router.post("/download", async (req, res) => {
let id = req.body.id;
id = parseInt(id);
let doc = await db.findOneAndUpdate({_id: id}, {downloads: 100});
});
Note: This works
But I'm trying to increase the number by 1 each time.
For example: Let's say the current number of downloads is 5, how do I do it that if there's a post request. The number of downloads increases by 1.
const { body: { id } } = req;
const intCasetedId = parseInt(id);
const retrievedDocument = await db.findOneAndUpdate({ id }, { $inc: { downloads: 1 } });
A couple things are happening here.
First I get the id value from the the req argument using a destructuring assignment.
I use only const to ensure I do not mutate variable values.
I also use the object property value shorthand notation to skip '_id' key in the search query argument. Quoting mongoose documentation:
Issues a mongodb findAndModify update command by a document's _id field. findByIdAndUpdate(id, ...) is equivalent to findOneAndUpdate({ _id: id }, ...).
Then I am using '$inc' operator to increment the downloads field by 1.
I would also highly recommend for you to research eslint

return updated entity with entityRepository

Is there any way to update an entity and return the result of the operation USING entity repository and NOT query Builder?
const result = await this.shipmentRepository.createQueryBuilder('sh')
.update()
.set({ ...infoToUpdate })
.where('shipment_number = :shipmentNumber', { shipmentNumber })
.returning("*")
.execute()
return result.raw[0]
I'm using this ^, this works properly but I want to know if I can do it using this syntaxis
const result = await this.shipmentRepository.update({ shipment_number: shipmentNumber }, infoToUpdate)
TypeORM documentation doesnt say anything about it
Can you help me? Thank u a lot!

how to use "where" on a query with entity repository from table relations

I am trying to do a query that with query builder works fine but when I try to do it with entity repository fails.
Anyone can tell me what I am doing wrong?
Query Builder query
const dispatchHeader2 = await this.dispatchHeaderRepository.createQueryBuilder('dh')
.innerJoinAndSelect('dh.driver', 'driver')
.innerJoinAndSelect('dh.vehicle', 'vehicle')
.innerJoinAndSelect('vehicle.transportCompany', 'vtc')
.innerJoinAndSelect('dh.order', 'o')
.where('dh.order_id IN(:...ordersId)', { ordersId })
.andWhere('o.local_origin = :selected_dc', { selected_dc })
.getMany()
Query with Entity Repository
const dispatchHeader = await this.dispatchHeaderRepository.find({
relations: ['driver', 'vehicle', 'vehicle.transportCompany', 'order'],
where: {
order_id: In(ordersId),
order: {local_origin:selected_dc }
}
})
Relation on BD
If i do the query without the
order: {local_origin:selected_dc }
works fine, if i Add that line all fails
Thanks for the help.
img from typeorm Docs
Answering Youba
Dont let me do that
And the query doesnt give me an error, just an empty result. But the query itself dont take any parameters

JSON.parse fails on ObjectId

I am trying to convert a string for use in mongodb but fails.
let pipeline = JSON.parse('[{"$match": {"_id": ObjectId("5b5637acbd3e9c2068ef80c3")}]');
// results in "SyntaxError: Unexpected token O in JSON at position 20"s
let pipeline = JSON.parse('[{"$match": {"_id": "5b5637acbd3e9c2068ef80c3"}]');
let response = await db.collect('<collection_name>').aggregate(pipeline).toArray();
// returns [] parse works but mongodb doesn't return any rows!
// This works but its not the solution I am looking for.
let pipeline = [{"$match": {"_id": ObjectId("5b5637acbd3e9c2068ef80c3")}];
let response = await db.collect('<collection_name>').aggregate(pipeline).toArray();
I tried using the BSON type but had no luck.
My current work around is to remove the ObjectId() from the string and use a Reviver function with JSON.parse
const ObjectId = require('mongodb').ObjectID;
let convertObjectId = function (key,value){
if (typeof value === 'string' && value.match(/^[0-9a-fA-F]{24}$/)){
return ObjectId(value);
} else {
return value;
};
}
let pipeline = JSON.parse('[{"$match": {"_id": "5b5637acbd3e9c2068ef80c3"}]',convertObjectId);
let response = await db.collect('<collection_name>').aggregate(pipeline).toArray();
// returns one record.
Unfortunately, [{"$match": {"_id": ObjectId("5b5637acbd3e9c2068ef80c3")}] is not valid JSON.
The value of a property in JSON can only be an object (ex.: {}), an array (ex.: []), a string (ex.: "abc"), a number (ex.: 1), a boolean (ex.: true), or null. See an example of these values here: https://en.wikipedia.org/wiki/JSON#Example.
What you could do is add ObjectId() manually after parsing the JSON. This would mean that the value of _id would be a string first, which is valid JSON.
Then, you can loop through your parsed JSON to add ObjectId (see reference here: https://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html):
const ObjectId = require('mongodb').ObjectID;
const pipeline = JSON.parse('[{"$match": {"_id": "5b5637acbd3e9c2068ef80c3"}]');
const pipelineWithObjectId = pipeline.map(query => ({
$match: {
...query.$match,
_id: ObjectId(query.$match._id)
}
});
const response = await db.collect('<collection_name>').aggregate(pipelineWithObjectId).toArray();
This should work with the example you provided but there are multiple caveats:
Parsing a query like that could be a vulnerability if the string contains user input that has not been sanitized: https://blog.websecurify.com/2014/08/hacking-nodejs-and-mongodb.html.
This particular code snippet would only work for queries with $match, which means that this code is not very scalable.
This code is not elegant.
All these reasons, for what they are worth, make me think that you would be better off using an object rather than a string for your queries.

How to search data in mongodb with dynamic fields using mongoose?

I've a node.js api in which user sends the required fields as an array to be fetched from the mongodb database. I need to find the data of that fields using Find query. I've written forEach statement to loop through that array and got the array elements. But when I try to get the results by inserting the array elements in the query, it doesn't giving the required results. Could any one please help me in resolving the issue by seeing the code below?
templateLevelGraphData: async function(tid,payload){
let err, templateData, respData = [], test, currentValue;
[err,templateData] = await to(Template.findById(tid));
var templateId = templateData.templateId;
payload.variables.forEach(async data=>{
console.log(data); //data has the array elements like variables=["humidity"]
[err, currentValue] = await to(mongoose.connection.db.collection(templateId).find({},{data:1}).sort({"entryDayTime":-1}).limit(1).toArray());
console.log(currentValue);
});
return "success";
}
The expected output is,
[ { humidity: 36 } ]
But I'm getting only _id like,
[ { _id: 5dce3a2df89ab63ee4d95495 } ]
I think data is not applying in the query. But I'm printing the data in the console where it's giving the correct results by displaying the array elements like, humidity. What I need to do to make it work?
When you are passing {data: 1} you are passing an array where is expecting name of column.
You have to create an object where the keys are going to be the elements of the array and set them to 1.
const projection = data.reduce((a,b) => (a[b]=1, a), {});
[...] .find({}, projection) [...]
Actually I got the solution.
for(let i=0;i<payload.variables.length;i++){
var test = '{"'+ payload.variables[i] +'":1,"_id":0}';
var query = JSON.parse(test);
[err, currentValue] = await to(mongoose.connection.db.collection(templateId).find({"deviceId":deviceId},query).sort({"entryDayTime":-1}).limit(1).toArray());
console.log(currentValue); //It's giving the solution
}

Resources