I have a query for doing a lookup on two other collections, one contains information about students, other contains information about classes. The collection I'm running the query contains information about activities.
The things is: I can't compare a field from the second lookup I've done (on classes), for some reason the fields I add don't seem to work on the project field either.
Here's my query:
[
{"$lookup":{
"from":"students",
"localField":"class_id",
"foreignField":"classes_registered",
"as": "std"
}},
{"$unwind":"$std"},
{"$addFields":{"id_cls":{"$toString":"cls._id"},
"cls_name":"$$cls.name"
}},
{"$lookup":{
"from":"classes",
"localField":"class_id",
"foreignField":"id_cls",
"as": "cls"
}},
{"$unwind":"$std"},
{"$match":{
"$expr":{
"$and":[{
"$eq":["$std.email", filters["email"]]
},
{
"$eq":["$cls.name", filters["class_name"]]},
]
}
}
},
{"$project":{
"_id":0,
"cls.name":1,
"title":1,
"info":1,
"date_start":1,
"date_final":1,
"list":1
}}
]
"cls.name" shows always as "[ ]" on the response from query and
"$eq":["$cls.name", filters["class_name"]},
also doesn't compare to anything.
student collection sample:
{"_id":{"$oid":"60e3bfef0046de182072361d"},
"name":"matheus",
"date":{"$date":"2021-07-06T02:29:03.974Z"},
"email":"math#math",
"classes_registered":["60b4753f7976fb83300918f0","60b477557976fb83300918f2"]}
classes collection sample:
{"_id":{"$oid":"60b477557976fb83300918f2"},
"name":"desenho",
"teachers":["60b474937976fb83300918f1","60b474937976fb83300918ee"],
"date":{"$date":"2021-05-31T05:42:45.232Z"}}
classes_activities sample:
{"_id":{"$oid":"60e4c88ee19fb3797390b3f9"},
"title":"Trabalho Discente Efetivo II",
"info":"Desenhar em perspectiva cavallera a formiga apresentada em aula",
"date_start":{"$date":"2021-07-06T02:00:00.000Z"},
"date_final":{"$date":"2022-07-06T02:00:00.000Z"},
"list":1,
"class_id":"60b477557976fb83300918f2"}
Related
I am building a forum web app where user can like/dislike post of other users.
I have the following model, representing a Post:
[
{
_id:"0002253,
title:"My first post",
likes:[],
dislikes:[]
},
{
_id:"0002254,
title:"My second post",
likes:[],
dislikes:[]
},
{
_id:"0002255,
title:"My third post",
likes:[],
dislikes:[]
},
]
When a user sends a like or dislike, the latter's ID will be inserted into the corresponding array (like or dislike).
Each user can, for each post, insert only a like or a dislike (not both).
The query I used for the insert is the following:
let vote_result = await Poll.updateOne(
{
_id: poll_id,
$and: [
{ "likes": { $nin: [MY_ID] } },
{ "dislikes": { $nin: [MY_ID] }},
],
},
{
$addToSet: {
"likes": MY_ID,
},
},
So, theoretically, query should insert MY_ID in likes or dislikes array if and only if MY_ID is not present in either array.
The problem is that query still writes MY_ID in likes array (even if MY_ID is present in dislikes) and vice versa.
Let's suppose now I want to leave a 'Like' to a post:
Phase 1:
likes:[]
dislikes:[]
(I am able to like or dislike, it works.)
Phase 2:
likes: [MY_ID]
dislikes:[]
(I am not able send like again, it works, but I am still able to dislike - it should not allow me to vote again.)
I am using sequelize .literal function to create an aggragated field, which was not achievable in other ways. Now I want to use sequelize's built-in "where" clause to filter by values on this new field.
DB_A.findAll({
attributes: {
include: [
[
sequelize.literal(
`(SELECT COUNT (*) FROM DB_B as DB_B WHERE DB_B.a_id = DB_A.id)`
),
"b_count",
],
]}
where:{ b_count:{[Op.gte]:10}}
})
When I do this, I get "Unknown column 'DB_A.b_count' in 'where clause'". I've also tried:
where:{[sequelize.literal("b_count")]:...}
Which works with the order property from sequelize, but not here.
Any ideas?
Ok, I figured it out. You need to use "having" instead of "where", as it would be the way to do with regular MySQL. For some reason Sequelize.having is not on the DOCS/API, and I already opened an issue at the git repo.
The above code would then be:
DB_A.findAll({
attributes: {
include: [
[
sequelize.literal(
`(SELECT COUNT (*) FROM DB_B as DB_B WHERE DB_B.a_id = DB_A.id)`
),
"b_count",
],
]}
having:{ ["b_count"]:{[Op.gte]:10}}
})
Objective:
Create a hashtagging system against a Product
Models:
Products
Hashtags
ProductTags (join table)
What I'm doing
When I create a new product the following happens:
Product is created
Hashtag is created
ProductTag join is created
The data looks like this:
{
"category_id":2,
"description":"Some description",
"price": 45,
"currency_id": "GBP",
"hashtags":[
{"tag":"tagnumber1"},
{"tag":"tagnumber2"},
{"tag":"tagnumber3"}
]
}
The Product.create code looks like this:
models.Product.create(data, {
include: [
{
model: models.Hashtag,
as: "hashtags",
attributes: models.Hashtag.fields
}
]
});
Issue
When I create the product for the first time with tag: tagnumber1, tagnumber2,tagnumber3. It adds these into the Hashtag table and creates the relation in the ProductTag table.
But when I create another product with the same tag: tagnumber1, tagnumber2,tagnumber3. It still adds these same tags into the Hashtag table.
How?
Is it possible on the second add to still have it INSERT into ProductTags but instead of duplicating the tags in Hashtag to grab the ids if they match?
I've got a rather specific case: Using mongoose/mongo and user objects
I want to find and update user in one call.
DB.collection('users').findOneAndUpdate({localId: id} ,{ "$set": { "name": "lla", "usnme": "As"} } ,callback);
Note that 'username' is spelled wrong. Yet mongo updated the first field(name) and does not give any error about the second.
How can I validate the keys I pass in $set without making more than one query?
What MongoDB suggests here is called schema validation:
In your specific case you could run the following command to make sure that no additional ("incorrect") fields can be added by anyone:
db.runCommand({ "collMod": "users", "validator": {
$jsonSchema: {
additionalProperties: false,
properties: {
"_id": {
bsonType: "objectId"
},
"name": {
bsonType: "string"
},
"username": {
bsonType: "string"
}
}
}
}})
Beyond that I cannot really think of any solution since MongoDB is a document database which by default is schemaless and hence won't stop you from creating the fields you tell it to create...
this below Sequelize work fine for me without using order, i'm wondering why i can't use order for root table as posts model? when i use this below code i get this error:
Unhandled rejection Error: 'posts' in order / group clause is not valid association
but that work fine on other models such as channelVideoContainer
models.posts.findAll({
where: {
channelId: 1
},
include: [
{
model: models.channelVideoContainer,
include: [models.fileServerSetting]
}, {
model: models.channelMusicContainer,
include: [models.fileServerSetting]
}, {
model: models.channelImageWithTextContainer,
include: [models.fileServerSetting]
}, {
model: models.channelFilesContainer,
include: [models.fileServerSetting]
},
models.channelPlainTextContainer
], order: [
[{model: models.posts}, 'id', 'DESC'],
], limit: 5
}).then(function (result) {
console.log(JSON.stringify(result));
});
You are getting this error because you are querying the posts table/model, and then sorting by a column on the posts model, however you are specifying a "joined" table in your order. This works for your other models because they are in fact joined (using the include option). Since you are querying the posts model you just need to pass in the name of the column you want to order by. See some of the ORDER examples in the documentation.
// just specify the 'id' column, 'post' is assumed because it is the queried Model
order: [['id', 'DESC']],
As a side note, you may want to specify required: false on your include'd models to perform a LEFT JOIN so that rows come back even if there are no matches in the joined table. If you know that rows will be returned (or they are actually required) then leave it as is.
{
model: models.channelFilesContainer,
include: [models.fileServerSetting],
required: false, // LEFT JOIN the channelFilesContainer model
},