How to $match a field conditionally in mongo DB - javascript

I have the following schema:
User: {
...otherFields,
isDumb: false,
type: "A" // could be "A", "B", or "C"
}
I want to fetch all dumb users by default and fetch by type only if the type is passed through the parameters.
static async getUsers(req: any, res: Response) {
const { type = "" } = req.params;
const queryPipeline = [
{
$match: {
isDumb: true,
type: // I want to only filter by type if the param is passed in
}
}
]
const users = await User.aggregate(queryPipeline);
So if my data was:
[
{
...otherFields,
isDumb: false,
type: "A"
},
{
...otherFields,
isDumb: true,
type: "B"
},
{
...otherFields,
isDumb: true,
type: "C"
}
]
and req.params.type was "B", I should get back:
[
{
...otherFields,
isDumb: true,
type: "B"
}
],
if req.params.type was undefined, I should get all dumb users
[
{
...otherFields,
isDumb: true,
type: "B"
},
{
...otherFields,
isDumb: true,
type: "C"
}
]

you just have to build an object and pass it to match
const matchParams = req.params.type ? {isDumb:true,type:req.params.type } : {isDumb:true }

You can create the object using JS:
const params = "A" // get req.params as you want
let query = {$match:{isDumb:true}}
if(params) query.$match.type = params
console.log(query)

First, you don't need to use Aggregation Framework for simple find query. You can use find method instead.
Second, consider approach where you initialize the filter with isDumb: true, and add new type property only if req.params.type exists.
let filter = { isDumb: true };
if(req.params.type) filter.type = req.params.type;
const users = await User.find(filter);

Related

nodejs mongodb type objeactId array doesnt save as ObjeactId array, instead it save as Strings array

I need to migrate some data to my local mongodb database. so I created a seed function to save data to database from a CSV file. In my schema object I specify "members" field as Types.ObjectId[]. But instead it saves string values array.
This is a saved document
This is my Schema
const schemaOptions: mongoose.SchemaOptions = {
_id: true,
id: false,
timestamps: true,
skipVersioning: true,
strict: false,
toJSON: {
getters: true,
virtuals: true,
},
};
const UnreadMessageSchema = new mongoose.Schema({
unreadUserId: { type: Schema.Types.ObjectId },
msgCount: { type: Schema.Types.Number },
lastMessage:{ type: Schema.Types.ObjectId ,ref: "Message",}
});
export const ChatSchema = new mongoose.Schema(
{
members: [
{
type: Schema.Types.ObjectId,
ref: User.modelName,
},
],
lastActiveTime: {
type: Schema.Types.Date,
},
isActive: { type: Schema.Types.Boolean, default: true },
unreadMessage: {
type: UnreadMessageSchema,
},
},
schemaOptions
);
const Chat = mongoose.model<IChatData>("Chat", ChatSchema);
export default Chat;
This is my migration function
export async function createChatInnerFunctionComechatMigration(therpistId: string, clientId: string) {
try {
const members = [mongoose.Types.ObjectId(therpistId), mongoose.Types.ObjectId(clientId)];
const chatData: ChatData = {
isActive: true,
lastActiveTime: new Date(),
members: members.map((id) => {
return id;
}),
unreadMessage: null,
};
const createChat = await ChatDao.createChat(chatData);
if (!createChat) {
return "Creating chat failed";
}
return createChat;
} catch (err) {
return "Something went wrong with chat creation";
}
}
My question is why "members" array save as string arrays. It should save as ObjeactId Array

Mongoose does not produce a result but mongo shell does

I have schema for products and it has a field storeZones object in it defined as
...
storeZones: {
type: {
masterZone: {type: Schema.Types.ObjectId, model: 'Zone', index: 1 },
zone: { type: Schema.Types.ObjectId, model: 'Zone', index: 1 },
subZone: { type: Schema.Types.ObjectId, model: 'Zone', index: 1 },
},
default: {
masterZone: null,
zone: null,
subZone: null,
},
},
...
I am counting for products in a specific masterZone. So my query is
const condition = { 'storeZones.masterZone': masterZone };
console.log(condition); // { 'storeZones.masterZone': '60533e6a745d465ab6cb3fc9' }
const total = await Product.count(condition);
This returns 0 results.
But when i paste the exact query in mongo shell; Robo3t to be exact.
db.products.find({'storeZones.masterZone': ObjectId('60533e6a745d465ab6cb3fc9') } )
It produces the desired output. Can someone please provide some assistance?
Fixed it by converting the masterZone from request to an ObjectId. Idk why i needed to do this, but that fixed it! so...
const m = mongoose.Types.ObjectId(masterZone);
const condition = { 'storeZones.masterZone': m };
console.log(condition); // { 'storeZones.masterZone': '60533e6a745d465ab6cb3fc9'}
const total = await Product.count(condition);

use mongooseModel.find() on schema that has a Schema.Types.Mixed property

I have trouble using postModel.find() query in a schema that defined as Schema.Types.Mixed.
this is a sample of my schema
const PostSchema = new mongoose.Schema({
//.....
address: {
type: String,
required: true,
},
postDetails: {
type: Schema.Types.Mixed,
required: true,
},
author: {
type: Schema.Types.ObjectId,
ref: 'User',
},
//.....
});
this is a sample document stored in db
{
//.....
"state": "Lakes State",
"address": "some address",
"postDetails": {
"type": "Cages",
"condition": "Used"
},
//......
}
it is giving me an empty array if I use this
const queryObject = {
postDetails: {
type: 'Cages',
},
};
return this.postModel.find(queryObject);
but it gives the desired results if I include all the properties like this
const queryObject = {
postDetails: {
type: 'Cages',
condition: 'Used',
},
};
return this.postModel.find(queryObject);
How do i get all matching posts that have postDetails.type = 'Cages' ? without knowing all available properties inside postDetails
there are some similar questions about this here. but most of them are using arrays instead of an object
You can use dot notation for querying embedded documents
postModel.find({
"postDetails.type": "Cages"
});

Information isn't being passed to an array via Mongoose, can't work out why

Apologies if this has been answered before, I have checked other answers and can't work it out from those.
I have a set of information that I would like placed into an array named "teamDetails". Here is the relevant /post item from server.js:
app.post('/create', (req, res) => {
console.log('Post command received');
console.log(req.body);
console.log(req.body.data.teamDetails[0]);
//We need to push the variable below, 'teamDetails', as an object into an array of the same name
var teamDetailsObj = {
// Modified for Postman
"teamName": req.body.data.teamDetails[0].teamName,
"teamNameShort": req.body.data.teamDetails[0].teamNameShort,
"teamfounded": req.body.data.teamDetails[0].teamFounded,
"teamHome": req.body.data.teamDetails[0].teamHome
};
console.log(teamDetails);
var newTeam = new Team({
"data.added": new Date(),
"data.entry": req.body.data.entry
});
newTeam.save().then((doc) => {
console.log("This is newTeam.data: " + newTeam.data);
console.log("This is teamDetailsObj: " + teamDetailsObj);
newTeam.data.teamDetails.push(teamDetailsObj);
var teamId = doc.id;
res.render('success.hbs', {teamId});
console.log("Team Added - " + teamId);
}, (e) => {
res.status(400).send(e);
});
});
Here is my team.js model:
var mongoose = require('mongoose');
var ObjectID = mongoose.Schema.Types.ObjectId;
var Mixed = mongoose.Schema.Types.Mixed;
var Schema = mongoose.Schema;
var Team = mongoose.model('Team', {
data: {
entry: {
type: String,
default: "USER.INPUT"
},
added: {
type: Date,
default: Date.Now
},
teamDetails: [
{
teamName: {
type: String,
trim: true,
required: true,
default: "First Team"
},
teamNameShort: {
type: String,
trim: true,
uppercase: true,
maxlength: 3,
required: true
},
teamFounded: {
type: Number,
maxlength: 4
},
teamHomeCity: {
type: String
}
}
]
}
});
module.exports = {Team};
Lastly, the sample data I'm trying to inject via Postman:
{
"data": {
"entry": "Postman.Entry",
"teamDetails": [
{
"teamName": "Test Teamname",
"teamNameShort": "TTN",
"teamFounded": "1986",
"teamHome": "London",
"players": [
{
"player1Name": "Test Player 1",
"player1Position": "Forward",
"player1Nationality": "GBR"
},
{
"player2Name": "Test Player 2",
"player2Position": "Defender",
"player2Nationality": "UKR"
},
{
"player3Name": "Test Player 3",
"player3Position": "Goaltender",
"player3Nationality": "IRL",
"captain": true
}
],
"coachingStaff": {
"headCoach": "Derp McHerpson",
"teamManager": "Plarp McFlarplarp"
}
}
]
}
}
(Disregard the players section, it's another kettle of fish)
As a result of using my code above, the resulting entry for teamDetails is just an empty array. I just can't get my code to push the teamDetailsObj into it.
Any help anyone can provide is appreciated.
It looks like you add teamObjDetails AFTER saving it with newTeam.save().then( ... )
I'm not a lot familiar with Mongoose but I don't see how could the team details could be present if not added before saving.
Let me know if it changes something !
A. G

React - Loop through multiple nested arrays json object response then update State

I have some data that has the following shape. The schedule data also has other identifying information attached to it, being schedules.included which is an array of arrays. I want to loop through each included array and find it by type element. I'm not entirely sure how to get each included[] by type then update state with data from each array, respectively. Is forEach the correct approach?
const schedules = {
data: [
{
id: "2147483610",
type: "Schedule"
}
],
included: [
{
id: "21468486",
type: "Query",
name: "Query1"
},
{
id: "43573457345",
type: "DataSource",
name: "DataSource1"
}
]
};
I then want to update state with whatever data I need.
getData = () => {
axios({
method: "get",
url: `/endpoint/with/this/data`
})
.then(response => {
console.log(response);
var obj = schedules.included[i].type;
obj.forEach(function(type) {
alert(type.name);
});
this.setState({
schedules: schedules.data,
//update with name from type Query
});
})
.catch(error => console.log(error.response));
};
If you want to find the name of the element from the included array which has type = Query, and there is only one such element:
var query = schedules.included.find(el => el.type == "Query");
console.log(query.name); // output Query1
If there is more than one query element you could use filter to get all query elements, then loop thru them doing stuff with each one.
var queries = schedules.included.filter(el => el.type == "Query");
queries.forEach(q => console.log(q.name));
If there is only one element with the type you are looking for then you can use find or if there is more use filter.
const schedules = {
data: [
{
id: "2147483610",
type: "Schedule"
}
],
included: [
{
id: "21468486",
type: "Query",
name: "Query1"
},
{
id: "43573457345",
type: "DataSource",
name: "DataSource1"
}
]
};
const typeMatched = schedules.included.find( included => included.type === "Query");
console.log(': ', typeMatched);
const schedulesObj = {
data: [
{
id: "2147483610",
type: "Schedule"
}
],
included: [
{
id: "21468486",
type: "Query",
name: "Query1"
},
{
id: "43573457345",
type: "DataSource",
name: "DataSource1"
},
{
id: "21468482",
type: "Query",
name: "Query2"
},
{
id: "21468484",
type: "Query",
name: "Query3"
},
]
};
const typeMatchedArray = schedulesObj.included.filter( included => included.type === "Query");
console.log('Query Type List: ', typeMatchedArray)

Categories

Resources