mongoose-mpath module is creating the document but not assigned to it's parent - node.js

const {category, parent} = newCategory;
const newCat = new Category({
_id: new mongoose.Types.ObjectId(),
name: category,
parent: parent
}).save((err, res) => {
if(err) { console.log(err)}
else{
console.log("res in create category:", res);
// io.to(user.room).emit('create-category-to-list', {res});
}
})
In log
res in create category: {
codewords: [],
children: [],
_id: 604916cf866a154e284b2e29,
name: 'nameofasdasdasdcat',
parent: 60490c9ce00e8b7a38cf4752,
path: '60490c9ce00e8b7a38cf4752#604916cf866a154e284b2e29',
_v:0
}
Here the document is created but not assigned to its parent why this is happening.
Here you can see parent children array is empty
root: {
children: [],
_id: 60490c9ce00e8b7a38cf4752,
name: 'root',
path: '60490c9ce00e8b7a38cf4752',
_v:0
}
Here i am using mongoose pulgin(mongoose-mpath) for create a tree form data.
For mongoose-mpath https://www.npmjs.com/package/mongoose-mpath

In getChildrenTree function need to pass options as lean:false
const parent = await Folder.findOne({ _id: user.rootId });
const tree = await parent.getChildrenTree(
{
populate: 'codewords',
options: { lean: false } //you need to pass options as lean: false
});
console.log({ tree });
In log
{
tree: [
{
codewords: [],
children: [],
_id: 604c6c5bc8a2e03ee43c4c7b,
name: 'Category-name-2',
parent: 604c690b87924705a401f9ce,
path: '604c690b87924705a401f9ce#604c6c5bc8a2e03ee43c4c7b',
__v: 0
},
{
codewords: [],
children: [],
_id: 604c6ce2c8a2e03ee43c4c7d,
name: 'Category-name-2',
parent: 604c690b87924705a401f9ce,
path: '604c690b87924705a401f9ce#604c6ce2c8a2e03ee43c4c7d',
__v: 0
},
{
codewords: [],
children: [Array],
_id: 604c6d21c8a2e03ee43c4c7e,
name: 'Category-name-3',
parent: 604c690b87924705a401f9ce,
path: '604c690b87924705a401f9ce#604c6d21c8a2e03ee43c4c7e',
__v: 0
}
]
}
for your better understanding you can check mongoose-mpath github issue section ==>
https://github.com/vikpe/mongoose-mpath/issues/10

Related

Filter data in Node.js

I want to subtract already booked data from totalSpots variable whenever this condition returns true
if(totalSpots > bookings.count()){
return true
}
return false
And when it return true I want to store it into a variable called filteredData.
GET route to fetch parking availability:
exports.getParkingListByCriteria = async (req, res) => {
try {
endTime = getEndTime(req.body.startTime, req.body.duration);
let parkings = await Parking.find(
{
"location.city": req.body.city,
}
);
let parkingList = [];
let parkingIds = [];
parkings.forEach((parking) => {
isParkingAvailable(parking.availability, req.body.startTime, endTime);
{
parkingList.push(parking);
parkingIds.push(parking._id);
}
});
const bookings = await Booking.find({
"isBookingCancelled.value": false,
parkingId: { $in: parkingIds },
});
let groupBookings = {};
let tmppid = "";
bookings.forEach((booking) => {
tmppid = booking.parkingId.toString();
if (typeof groupBookings[tmppid] === "undefined")
groupBookings[tmppid] = [];
groupBookings[tmppid].push(booking);
});
var keys = Object.keys(groupBookings);
console.log("parkingList -> ", parkingList);
parkingList.filter((booking) => {
isParkingSlotAvailable(groupBookings, Object.keys(groupBookings));
}); //Stuck in the function
res.status(200).send(parkingList);
} catch (error) {
return res.status(500).json({ error: error.message });
}
};
isParkingSlotAvailable Function:
exports.isParkingSlotAvailable = (groupBookings, keys) => {
groupBookings.forEach((booking) => {});
};
The sample data from console.log(parkingList)
parkingList -> [
{
contactInfo: { name: 'Claudia Shields', phoneNumber: 8904672101 },
location: {
address: '737 applegate court',
city: 'bowie',
state: 'rhode island',
country: 'greece',
zipCode: 10825
},
coordinates: { lng: 34.048954, lat: 10.299556 },
_id: new ObjectId("62d12053cb03235286511d54"),
merchantId: new ObjectId("62c950dfc96c2b690028be88"),
price: 16,
parkingType: 'residence',
parkingInfo: [ [Object] ],
totalSpots: [ 127 ],
status: 'active',
isFeePaid: false,
parkingZone: [],
availability: [ [Object], [Object], [Object], [Object], [Object], [Object] ],
specialEvents: [],
createdAt: 2022-07-15T08:07:47.997Z,
updatedAt: 2022-07-15T09:29:58.696Z,
__v: 0
},
]
The sample data from console.log(groupBookings)
groupBookings: {
'62d12053cb03235286511d54': [
{
duration: [Object],
isBookingCancelled: [Object],
_id: new ObjectId("62d2a9d1cf93195bef1923af"),
parkingId: new ObjectId("62d12053cb03235286511d54"),
user: new ObjectId("62c95116c96c2b690028be8e"),
date: 2022-07-22T00:00:00.000Z,
startTime: 2022-07-22T05:30:00.000Z,
endTime: 2022-07-22T08:40:00.000Z,
isFeePaid: false,
status: 'sent',
isStarted: false,
isEnabled: false,
createdAt: 2022-07-16T12:06:42.002Z,
updatedAt: 2022-07-16T12:15:08.578Z,
__v: 0
},
{
duration: [Object],
isBookingCancelled: [Object],
_id: new ObjectId("62d553f80e8fa13f1295514c"),
parkingId: new ObjectId("62d12053cb03235286511d54"),
user: new ObjectId("62c95136c96c2b690028be9a"),
date: 2022-07-22T00:00:00.000Z,
startTime: 2022-07-22T10:30:00.000Z,
endTime: 2022-07-22T12:30:00.000Z,
isFeePaid: false,
status: 'sent',
isStarted: false,
isEnabled: false,
createdAt: 2022-07-18T12:37:12.682Z,
updatedAt: 2022-07-18T12:37:12.682Z,
__v: 0
}
]
}
Try to change your filter function like this.
Also, make sure that you update the parkingList since filter does not edit the array in-place.
parkingList = parkingList.filter((booking) => {
const booked = groupBookings[booking._id];
const alreadyBooked = booked ? booked.length : 0;
return booking.totalSpots[0] > alreadyBooked;
});

how can send new added item in nested object as response

I have a collection with name User in my mongodb for the example you can see in below a sample of saved user
{
_id: new ObjectId("61488f3892099143ca2b2bbc"),
name: 'test',
orders: [],
products: [
{
name: 'as',
image: '049fcd8d-f954-4aef-bd77-757af881f7c5.jpeg',
_id: new ObjectId("61531666ad63a47ed692c90b")
},
]
}
I have function with node.js that has responsible to add new product to selected user
async function addProduct(req, res, next) {
await User.findOneAndUpdate(
{ _id: req.params.userId },
{
$addToSet: {
products: {
...req.body,
image: req.file.filename,
},
},
}
);
return res.status(200).send();
}
but I want to send only new added product as response
please help me to solve this problem.
I recommend you to use the $push operator (doc):
{ $push: { <field1>: <value1>, ... } }
Using it with your example:
(async () => {
await User.findByIdAndUpdate(
'6153769ce997d65baf860cc7',
{
$push: {
products: {
name: 'as2',
image: '589fcd8d-f954-4aef-bd77-757af881f7c5.jpeg'
}
}
}
);
})();

Elastic APM: Mongoose spans cannot find transaction when used with apollo/graphQL

I am using Elastic APM. I find that mongoose integration is not working when used with GraphQL/Apollo Server somehow. I wrote an apollo-server plugin like this to start/stop transactions:
import apm from 'elastic-apm-node/start';
import _ from 'lodash';
import { gql } from 'apollo-server-express';
const apmPlugin = {
requestDidStart: (requestContext) => {
const query = gql`${requestContext.request.query}`;
const type = _.get(query, 'definitions[0].operation', '');
const funcName = _.get(query, 'definitions[0].name.value', '');
const txnName = type && funcName ? `${type} ${funcName}` : '/gql';
const txn = apm.startTransaction(txnName, 'graphql');
return {
didEncounterErrors: (err) => {
if (txn) {
txn.result = err.errors.length === 1 ? err.errors[0].name : 'error';
}
},
willSendResponse: (res) => {
if (Array.isArray(res.response.errors).length === 0) {
txn.result = 'success';
}
if (typeof txn?.end === 'function') txn.end();
},
};
},
};
It works, but I am missing spans from mongoose, when I enable trace, this is what I see:
start trace {
trans: 'ddc03cb86cf71448',
parent: undefined,
trace: '7127e63abe8e6d5086d36c13deee8183',
name: 'unnamed',
type: 'graphql',
subtype: null,
action: null
}
start span {
span: '94fc2307e19dd187',
parent: 'ddc03cb86cf71448',
trace: '7127e63abe8e6d5086d36c13deee8183',
name: 'GraphQL: Unknown Query',
type: 'db',
subtype: 'graphql',
action: 'execute'
}
intercepted call to graphql.execute { id: 'ddc03cb86cf71448' }
Mongoose: yyy.findOne({ domainSlug: 'xxx' }, { projection: {} })
no active transaction found - cannot build new span
Mongoose: yyy.findOne({ email: 'xxx', company: ObjectId("5f1ab19010469e8eb952e754") }}, { projection: {} })
no active transaction found - cannot build new span
Mongoose: roles.find({ _id: { '$in': [ ObjectId("5f1ab19010469e8eb952e786") ] } }, { skip: undefined, limit: undefined, perDocumentLimit: undefined, projection: {}})
no active transaction found - cannot build new span
ended span {
span: '94fc2307e19dd187',
parent: 'ddc03cb86cf71448',
trace: '7127e63abe8e6d5086d36c13deee8183',
name: 'GraphQL: xxx',
type: 'db',
subtype: 'graphql',
action: 'execute'
}
encoding span {
span: '94fc2307e19dd187',
parent: 'ddc03cb86cf71448',
trace: '7127e63abe8e6d5086d36c13deee8183',
name: 'GraphQL: xxx',
type: 'db'
}
sending span {
span: '94fc2307e19dd187',
parent: 'ddc03cb86cf71448',
trace: '7127e63abe8e6d5086d36c13deee8183',
name: 'GraphQL: xxx',
type: 'db'
}
sending transaction {
trans: 'ddc03cb86cf71448',
trace: '7127e63abe8e6d5086d36c13deee8183'
}
ended transaction {
trans: 'ddc03cb86cf71448',
parent: undefined,
trace: '7127e63abe8e6d5086d36c13deee8183',
type: 'graphql',
result: 'success',
name: 'mutation doLogin'
}
Notice the spans created fine before and after those mongoose calls, but the mongoose calls seem to be unable to find the active transaction somehow.
no active transaction found - cannot build new span

All nested rows does not inserted in a table

I want tree structure in my Categories table.
So I tried this:
Categories model looks like:
import * as Sequelize from 'sequelize';
export default class CategoriesModel extends Sequelize.Model {
static init(sequelize, DataTypes) {
return super.init({
name: {
type: DataTypes.STRING,
},
}, {
modelName: 'categories',
sequelize,
});
}
}
association in my CategoriesModel class looks like:
static associate({ Categories }) {
this.nestedCategories = this.hasMany(Categories, {
as: 'nestedCategories',
foreignKey: 'parentId',
});
}
and when i tried to insert rows, for example:
sequelize.sync({ force: true }).then(() => {
models.Categories.create({
name: 'parent',
nestedCategories: [
{
name: 'child 1',
},
{
name: 'child 2',
nestedCategories: [
{
name: 'child 3',
}
],
},
],
}, {
include: [models.Categories.nestedCategories]
}).then(cat => {
console.log(cat.toJSON());
})
});
result is:
{
id: 1,
name: 'parent',
nestedCategories:
[ { id: 2,
name: 'child 1',
parentId: 1,
updatedAt: 2019-02-05T08:39:45.655Z,
createdAt: 2019-02-05T08:39:45.655Z },
{ id: 3,
name: 'child 2',
parentId: 1,
updatedAt: 2019-02-05T08:39:45.657Z,
createdAt: 2019-02-05T08:39:45.657Z } ],
updatedAt: 2019-02-05T08:39:45.624Z,
createdAt: 2019-02-05T08:39:45.624Z,
parentId: null
}
child 3 does not inserted in a table.
I dont understand what i'm doing wrong...
You need to specify one include per nested category in order to make your request parsed correctly.
Here I made a function to do this recursively based on model you want to create:
function buildIncludeRecursive(model, includeTemplate) {
const include = Object.assign({}, includeTemplate);
let currInclude = include;
let currModel = model;
while(currModel[includeTemplate.as]){
currInclude.include = [Object.assign({}, includeTemplate)];
currInclude = currInclude.includes[0];
currModel = currModel[includeTemplate.as];
}
return include;
}
const model = {
name: 'parent',
nestedCategories: [
{ name: 'child 1' },
{
name: 'child 2',
nestedCategories: [
{ name: 'child 3' }
]
},
],
};
const includeTemplate = {
model: models.Categories,
as: 'nestedCategories'
};
model.categories.create(model, {
include: buildIncludeRecursive(model, includeTemplate)
});
Here's what your include is gonna be in this case:
{
model: models.Categories,
as: 'nestedCategories',
include: [
{
model: models.Categories,
as: 'nestedCategories'
}
]
}

Looping through objects and adding them to Sequelize db

I have an array of objects that I like to put into SQL via Sequelize and I'm running into issues.
[
{ owner: false,
id: '2342365',
name: 'awrAPI' },
{ owner: false,
id: '5675689699',
name: 'TgatAPI' },
{ owner: true,
id: '57456767',
name: 'ytasyAPI' }
[
Currently the way i have it set up is through a simple for in.
for( var key in guilds ) {
Guild
.findOrCreate({where: {primid: guilds[key].id}, defaults: {
primid: guilds[key].id,
name: guilds[key].name,
owner: guilds[key].icon
}})
.spread(function(guild, created) {
console.log(guild.get({
plain: true
}))
console.log(created)
})
}
I assume this is wrong and was wondering if there is a better way to loop through my object and chain the findorcreates. Currently it goes through the first object, but then does not add any more. I've been looking into using Bluebird, but I'm not too familiar with using promises. Thoughts?
var myData = [
{
owner: false,
id: '2342365',
name: 'awrAPI'
},
{
owner: false,
id: '5675689699',
name: 'TgatAPI'
},
{
owner: true,
id: '57456767',
name: 'ytasyAPI'
}
];
Promise.all(myData.map(function(value) {
// Do your thing
return Guild.findOrCreate...
})).then(function() {
// All is resolved do your next thing
})
An alternative would be to utilize squelize's bulkCreate model method for multiple records insertion.
link to sequelize's bulkCreate docs
quick snippet here:
const dataForInsertion = [
{
username:"daniel",
currentORM:"Sequelize"
},
{
username:"lekan",
currentORM:"Mongoose"
},
]
Guild.bulkCreate(dataForInsertion)
.then(()=>{})
.catch(()=>{})

Resources