String literals in JS API query - javascript

I'm currently utilizing the MTG API SDK (https://api.magicthegathering.io) that has a query structured as such:
// partial name match
mtg.card.where({name: 'Archangel Avacyn'})
.then(results => {
console.log(results)
})
// exact name match
mtg.card.where({name: '"Archangel Avacyn"'})
.then(results => {
console.log(results)
})
I have a REST API trying to access the SDK on the server by passing in a string value for the exact name of the card you want to find, like this:
exports.getCard = (req, res) => {
const card = req.params.card;
let query = "'\"" + card + "\"'";
console.log(query);
mtg.card.where({name : query})
.then(result=>{
res.send(result);
});
}
My problem is that is I use the variable req.params.card in the query I get the partial match return and if I use the query variable I get nothing. I need to exact match.
How can I get the exact match from passing in a variable instead of static text?

Related

filter in array doesn't work properly for me in nodeJS

I have a list of children that sits within one group, I tried to delete a child, and in addition to deleting him from the list. the deletion of the child is done well, but the child is not removed from the list in the group.
The data in MongoDB
The code in NodeJS.
I tried at first to delete the child with getByIdAndDelete() but I saw that after the child has been deleted the Node can't find it because it is deleted.
It seems the filtering doesn't work
What am I doing wrong?
Thanks for the help
NodeJS code:
router.delete("/delete-child/:id", (req, res) => {
const id = req.params.id;
Child.findOne({ _id: id })
.then((result) => {
Group.findOne({ _id: result.group }).then((resp) => {
resp.childrenList = resp.childrenList.filter(
(childId) => childId !== id
);
resp.save().then((savedResp) => {
console.log("deleteChild", savedResp);
});
});
res.send(result);
})
.catch((err) => {
console.log(err);
});
Child.findByIdAndDelete(id).then((deletedChild) => {
console.log("deletedChild", deletedChild);
});
});
When MongoDB automatically creates an _id, it is of type ObjectId.
In many Mongoose functions, such as Model.findByIdAndDelete a string argument is automatically cast to ObjectId.
In many other functions, there is no automatic cast. There is definitely no automatic cast in a non-mongoose function such as Array.filter.
This means that even if Child.findOne({ _id: id }) retrieves the correct group with a string instead of ObjectId, (childId) => childId !== id won't match.
To fix this, explicitly cast req.params.id to an ObjectId with:
const id = mongoose.Types.ObjectId(req.params.id);

Working SQL yields Syntax Error in pg-promise

I have the following code in one of my endpoints:
let setText = ''
for (const [ key, value ] of Object.entries(req.body.info)) {
setText = setText.concat(`${key} = ${value}, `)
}
// Last character always an extra comma and whitespace
setText = setText.substring(0, setText.length - 2)
db.one('UPDATE students SET ${setText} WHERE id = ${id} RETURNING *', { setText, id: req.body.id })
.then(data => {
res.json({ data })
})
.catch(err => {
res.status(400).json({'error': err.message})
})
It is supposed to dynamically generate the SQL from the request body. When I log the created SQL, it generates correctly. It even works when I directly query the database. However, whenever I run the endpoint, I get a syntax error that's "at or near" whatever setText is. I've tried using slice instead of substring with no change.
You should never concatenate values manually, as they are not escaped properly then, and open your code to possible SQL injections.
Use the tools that the library offers. For an UPDATE from a dynamic object, see below:
const cs = new pgp.helpers.ColumnSet(req.body.info, {table: 'students'});
const query = pgp.helpers.update(req.body.info, cs) +
pgp.as.format(' WHERE id = ${id} RETURNING *', req.body);
db.one(query)
.then(data => {
res.json({ data });
})
.catch(err => {
res.status(400).json({error: err.message})
});

Returning UID in Firebase query

The following query below returns me a collection of data based on a user id. How do I do I make sure it returns the uid of each document in the query.
getWebsitesByUserId(id) {
return this.afs.collection('websites', ref => ref.where('createdBy', '==', id)).valueChanges();
}
I understand that it involves something like this:
return this.afs.collection('websites').doc(id).snapshotChanges().pipe(map(action => {
const data = action.payload.data();
const uid = action.payload.id;
return {uid, ...data};
}));
Just not sure how to implement in a query.
According to this pull request on the AngularFire Repo now there is an option that you can pass a string to the valueChanges method on a collection reference.
This string will be the name of the property that will hold the IDs of the documents.
For example:
collectionRef.valueChanges('myIdKey').subscribe()
Would emit:
emits [ { myIdKey: 'MrfFpRBfWLTd7LqiTt9u', ...data }, ... ]
So in your situation I guess it would be something like this:
getWebsitesByUserId(id) {
return this.afs.collection('websites', ref => ref.where('createdBy', '==', id)).valueChanges('uid');
}

How can I insert an object graph by using MikroORM?

I'm trying to create and update multiple entities (models) at once. I did this in objection ORM by using insertGraph API which actually inserts entity if it has no id and updates if it has id.
Is there a similar API in MikroORM?
Currently I'm doing this:
app.put('/articles', async (req, res) => {
const save = req.body.articles.map(async (dto) => {
const article = Object.assign(new Article(), dto)
await req.em.persistAndFlush(article)
})
await Promise.all(save)
res.send({ ok: true })
})
but it generates multiple transactions and I want to everything in single transaction.
The problem here is that when using persistAndFlush method, you immediately persist the entity to database by awaiting the promise. Instead you can call em.persistLater(article) to mark it for persisting. Then call em.flush() afterwards, which will commit all changes to database inside single transaction.
app.put('/articles', async (req, res) => {
req.body.articles.forEach(dto => {
const article = Object.assign(new Article(), dto)
req.em.persistLater(article)
})
await req.em.flush() // save everything to database inside single transaction
res.send({ ok: true })
})
You can make it even simpler by preparing all entities into one array, and persistAndFlush that instead:
app.put('/articles', async (req, res) => {
const articles = req.body.articles.map(dto => Object.assign(new Article(), dto))
await req.em.persistAndFlush(articles) // save everything to database inside single transaction
res.send({ ok: true })
})
Also, instead of using Object.assign(), you can use IEntity.assign() method on the entity, which will also take care of creating references from plain identifiers:
const article = new Article().assign(dto)
More about IEntity.assign() can be found in the docs:
https://b4nan.github.io/mikro-orm/entity-helper/
You could also use EntityManager.create() helper, which will construct the entity for you - the benefit of this is that it will automatically handle constructor parameters, passing them to constructor instead of assigning them directly.
const article = req.em.create(Article, dto)

Extracting multiple observables into an already mapped stream angular rxjs

Currently building a project in Firebase and Angular 4. I am pulling in an object of data which contains many keys of data, and a lot of different uid keys.
To keep the data somewhat manageable i don't want to save the object data inside some keys where it can be changed at the host.
In the instance i have the uid stored, i want to create a new key of the extracted observable. I can easily add it as an observable inside the mapped object but i want to actually extract the observable into the object during the stream. Here is what i currently have:
this.ss.data()
.map(res => {
res['test1'] = this.fb.serie(res['serieUid']).map(res => res)
return res
})
.subscribe(res => {
console.log(res)
})
Result -
serieUid:"-Kk1FeElvKMFcyrhQP4T"
state:"Tennessee"
test1:FirebaseObjectObservable
timezone:"US/Eastern"
But i would like to have the extracted observable inside 'test1', I have failed on this for a few hours on this and am confused. There is more than one instance of a uid, so this was have to happen multiple times. Then subscribe.
Follow up after answered below:
Heres what i ended up with in my final function
getRound(roundUid: string) {
/**
Retrieves a round based simply on the uid
supplied.
**/
return this.fb.round(roundUid)
.mergeMap(round => // Get Serie Data
this.fb.serie(round['serieUid']).map(serie => {round['serie'] = this.cs.cleanForFb(serie); return round})
)
.mergeMap(round => // Get Type Data
this.fb.type(round['typeUid']).map(type => {round['type'] = this.cs.cleanForFb(type); return round})
)
.mergeMap(round => // Get sx Coast Data
this.fb.coast(round['sxCoastUid']).map(sxCoast => {round['sxCoast'] = this.cs.cleanForFb(sxCoast); return round})
)
}
Try this. The mergeMap() operator subscribes to the internal Observable whose result is using map() turned into the original res updated with test1.
this.ss.data()
.mergeMap(res => this.fb.serie(res['serieUid'])
.map(innerRes => {
res['test1'] = innerRes;
return res;
})
)
.subscribe(res => {
console.log(res)
})

Categories

Resources