How to add a custom method on a mongoose Model - javascript

In Mongoose, we can add methods to documents as follows:
const userSchema = new mongoose.Schema({
balance: Number
})
userSchema.methods.withdrawBalance = function(amount){
const doc = this
doc.balance = doc.balance - amount
}
and we can use it as follows:
const userDoc = UserModel.findById(ID_HERE);
userDoc.deductBalance(100); // -100$ USD
userDoc.save()
I want to be able to do the same on the models the same way I can do it on documents, I want to be able to something like that:
const userDoc = UserModel.findById(ID_HERE).myCustomMethod()
But How?

Hm I am not sure if I get you right but lets try.
const Order = mongoose.model("Order", orderSchema);
Order.test = function(){
console.log("Here I am!");
}
(async () => {
const o = await Order.findOne({}).test();
});

Related

Need help figuring out why calling methods from a mongoose schema works fine in one part of my node.js app, but fails elsewhere

I have created the following user schema, including two methods:
getSnapshot()
getLastTweetId()
user.js
const mongoose = require('mongoose')
const getLastTweetId = require('../utilities/getLastTweetId')
const getFollowers = require('../utilities/getFollowers')
const userSchema = new mongoose.Schema({
twitterId: {
type: String,
required: true
},
screenName: {
type: String
},
snapshots: {
type: [snapshotSchema],
default: []
},
createdAt: {
type: Date
},
})
userSchema.method('getSnapshot', async function () {
const { user, snapshot } = await getFollowers({user: this})
await user.save()
return snapshot
})
userSchema.method('getLastTweetId', async function () {
const tweetId = await getLastTweetId({user: this})
return tweetId
})
const User = mongoose.model('User', userSchema)
module.exports = User
When I define a user instance in passport.js, I can call getSnapshot() on user with no problems. (see below)
passport.js
const passport = require('passport')
const mongoose = require('mongoose')
const needle = require('needle')
const { DateTime } = require('luxon')
const User = mongoose.model('User')
// Setup Twitter Strategy
passport.use(new TwitterStrategy({
consumerKey: process.env.TWITTER_CONSUMER_API_KEY,
consumerSecret: process.env.TWITTER_CONSUMER_API_SECRET_KEY,
callbackURL: process.env.CALLBACK_URL,
proxy: trustProxy
},
async (token, tokenSecret, profile, cb) => {
const twitterId = profile.id
const screenName = profile.screen_name
const existingUser = await User.findOne({ twitterId })
if (existingUser) {
// Track if this is a new login from an existing user
if (existingUser.screenName !== screenName) {
existingUser.screenName = screenName
await existingUser.save()
}
// we already have a record with the given profile ID
cb(undefined, existingUser)
} else {
// we don't have a user record with this ID, make a new record
const user = await new User ({
twitterId ,
screenName,
}).save()
**user.getSnapshot()**
cb(undefined, user)
}
}
)
However, when I call getLastTweetId() on a user instance in tweet.js, I receive the following error in my terminal:
TypeError: user.getLastTweetId is not a function
Then my app crashes.
tweets.js
const express = require('express')
const mongoose = require('mongoose')
const User = mongoose.model('User')
const Tweet = mongoose.model('Tweet')
const { DateTime } = require('luxon')
const auth = require('../middleware/auth')
const requestTweets = require('../utilities/requestTweets')
const router = new express.Router()
const getRecentTweets = async (req, res) => {
const twitterId = req.user.twitterId
const user = await User.find({twitterId})
*const sinceId = user.getLastTweetId()*
let params = {
'start_time': `${DateTime.now().plus({ month: -2 }).toISO({ includeOffset: false })}Z`,
'end_time': `${DateTime.now().toISO({ includeOffset: false })}Z`,
'max_results': 100,
'tweet.fields': "created_at,entities"
}
if (sinceId) {
params.since_id = sinceId
}
let options = {
headers: {
'Authorization': `Bearer ${process.env.TWITTER_BEARER_TOKEN}`
}
}
const content = await requestTweets(twitterId, params, options)
const data = content.data
const tweets = data.map((tweet) => (
new Tweet({
twitterId,
tweetId: tweet.id,
text: tweet.text,
})
))
tweets.forEach(async (tweet) => await tweet.save())
}
// Get all tweets of one user either since last retrieved tweet or for specified month
router.get('/tweets/user/recent', auth, getRecentTweets)
module.exports = router
I would really appreciate some support to figure out what is going on here.
Thank you for bearing with me!
My first guess was that the user instance is not created properly in tweets.js, but then I verified via log messages that the user instance is what I expect it to be in both passport.js as well as tweets.js
My second guess was that the problem is that the user instance in the database was created before I added the new method to the schema, but deleting and reinstantiating the entire collection in the db changed nothing.
Next I went about checking if the issue is related to instantiating the schema itself or just importing it and it seems to be the latter, since when I call getLastTweetId in passport.js it also works, when I call getSnapshot() in tweets.js it also fails.
This is where I'm stuck, because as far as I can tell, I am requiring the User model exactly the same way in both files.
Even when I print User.schema.methods in either file, it shows the following:
[0] {
[0] getSnapshot: [AsyncFunction (anonymous)],
[0] getLastTweetId: [AsyncFunction (anonymous)]
[0] }
It looks like my first guess regarding what was wrong was on point, and I was just sloppy in verifying that I'm instantiating the user correctly.
const user = await User.find({twitterId})
The above line was returning an array of users.
Instead, I should have called:
const user = await User.findOne({twitterId})
I did not detect the bug at first, because logging an array that contains only one object looks nearly the same as just logging the object itself, I simply overlooked the square brackets.
Changing that single line fixed it.

How do you push a string into all users documents in a mongodb collection?

This is my subcommand code:
.addSubcommand(subcommand =>
subcommand
.setName('announcement')
.setDescription('Announce something to every user. ')
.addStringOption(option =>
option
.setName('announcement1')
.setDescription('Announcement content')
.setRequired(true))),
This is my code so far for the command:
if (interaction.options.getSubcommand() === 'announcement') {
const ann = interaction.options.getString('announcement1')
const notificationschema = require('./schemas/notificationschema')
}
I am trying to push the contents of the variable ann into everyone's notificationschema into the notifs array.
How would I do this?
This is my schema:
const mongoose = require('mongoose')
const notificationschema = mongoose.Schema({
User:String,
Notifs:Array,
Read:Boolean,
})
module.exports = mongoose.model('notification', notificationschema, 'notification')
You can use the find function from mongoose, then loop through all the found results.
const foundSchemas = await notificationSchema.find({});
foundSchemas.forEach(result => {
result.Notifs.push('Your Notification');
result.save();
})
You can use for looping function:
First, call your index:
const notificationschema = require('./schemas/notificationschema');
const notifs = await notificationschema.find({})
//This will make your data as array object.
Now After creating and calling your index. Use for loop:
for(let i = 0; i < notifs.length; i++) {
notificationschema.updateOne({
User: notifs[i].memberID //I assume that this column is a member_id
}, {
$push: {
Notifs: "Something you wanted to say here or whatsoever"
}
})
}

HyperLedger Fabric composer playground Reference error require not defined

I am trying to build a car auction network with composer playground the error occurs when I am at the stage to make an offer to an auction and after that every new registry I try to make gets this error Reference error: require not defined i am familiar with JavaScript but I am not sure what causing this error .
'use strict';
const AdminConnection = require('composer-admin').AdminConnection;
const BusinessNetworkConnection = require('composer-client').BusinessNetworkConnection;
const { BusinessNetworkDefinition, CertificateUtil, IdCard } = require('composer-common');
const path = require('path');
require('chai').should();
const NS = 'org.acme.vehicle.auction';
describe('CarAuction', () => {
// In-memory card store for testing so cards are not persisted to the file system
const cardStore = require('composer-common').NetworkCardStoreManager.getCardStore( { type: 'composer-wallet-inmemory' } );
let adminConnection;
let businessNetworkConnection;
before(async () => {
// Embedded connection used for local testing
const connectionProfile = {
name: 'embedded',
'x-type': 'embedded'
};
// Generate certificates for use with the embedded connection
const credentials = CertificateUtil.generate({ commonName: 'admin' });
// PeerAdmin identity used with the admin connection to deploy business networks
const deployerMetadata = {
version: 1,
userName: 'PeerAdmin',
roles: [ 'PeerAdmin', 'ChannelAdmin' ]
};
const deployerCard = new IdCard(deployerMetadata, connectionProfile);
deployerCard.setCredentials(credentials);
const deployerCardName = 'PeerAdmin';
adminConnection = new AdminConnection({ cardStore: cardStore });
await adminConnection.importCard(deployerCardName, deployerCard);
await adminConnection.connect(deployerCardName);
});
beforeEach(async () => {
businessNetworkConnection = new BusinessNetworkConnection({ cardStore: cardStore });
const adminUserName = 'admin';
let adminCardName;
let businessNetworkDefinition = await BusinessNetworkDefinition.fromDirectory(path.resolve(__dirname, '..'));
// Install the Composer runtime for the new business network
await adminConnection.install(businessNetworkDefinition);
// Start the business network and configure an network admin identity
const startOptions = {
networkAdmins: [
{
userName: adminUserName,
enrollmentSecret: 'adminpw'
}
]
};
const adminCards = await adminConnection.start(businessNetworkDefinition.getName(), businessNetworkDefinition.getVersion(), startOptions);
// Import the network admin identity for us to use
adminCardName = `${adminUserName}#${businessNetworkDefinition.getName()}`;
await adminConnection.importCard(adminCardName, adminCards.get(adminUserName));
// Connect to the business network using the network admin identity
await businessNetworkConnection.connect(adminCardName);
});
describe('#makeOffer', () => {
it('should add the offer to the offers of a vehicle listing', async () => {
const factory = businessNetworkConnection.getBusinessNetwork().getFactory();
// create the auctioneer
const seller = factory.newResource(NS, 'Member', 'daniel.selman#example.com');
seller.firstName = 'Dan';
seller.lastName = 'Selman';
seller.balance = 0;
// create the vehicle
const vehicle = factory.newResource(NS, 'Vehicle', 'CAR_001');
vehicle.owner = factory.newRelationship(NS, 'Member', seller.$identifier);
// create the vehicle listing
const listing = factory.newResource(NS, 'VehicleListing', 'LISTING_001');
listing.reservePrice = 100;
listing.description = 'My nice car';
listing.state = 'FOR_SALE';
listing.vehicle = factory.newRelationship(NS, 'Vehicle', 'CAR_001');
// create the buyer
const buyer = factory.newResource(NS, 'Member', 'sstone1#example.com');
buyer.firstName = 'Simon';
buyer.lastName = 'Stone';
buyer.balance = 1000;
// create another potential buyer
const buyer2 = factory.newResource(NS, 'Member', 'whitemat#example.com');
buyer2.firstName = 'Matthew';
buyer2.lastName = 'White';
buyer2.balance = 100;
// create the auctioneer
const auctioneer = factory.newResource(NS, 'Auctioneer', 'boss#auction.com');
auctioneer.firstName = 'Mr';
auctioneer.lastName = 'Smith';
const offer = factory.newTransaction(NS, 'Offer');
offer.member = factory.newRelationship(NS, 'Member', buyer.$identifier);
offer.listing = factory.newRelationship(NS, 'VehicleListing', 'LISTING_001');
offer.bidPrice = 200;
// Get the registries.
const vehicleRegistry = await businessNetworkConnection.getAssetRegistry(NS + '.Vehicle');
const vehicleListingRegistry = await businessNetworkConnection.getAssetRegistry(NS + '.VehicleListing');
const userRegistry = await businessNetworkConnection.getParticipantRegistry(NS + '.Member');
const auctioneerRegistry = await businessNetworkConnection.getParticipantRegistry(NS + '.Auctioneer');
// Add the Vehicle to the asset registry.
await vehicleRegistry.add(vehicle);
// Add the VehicleListing to the asset registry
await vehicleListingRegistry.add(listing);
// add the members
await userRegistry.addAll([buyer, buyer2, seller]);
// add the auctioneers
await auctioneerRegistry.addAll([auctioneer]);
// Create the offer transaction and submit
await businessNetworkConnection.submitTransaction(offer);
// Create the offer transaction and submit
const lowOffer = factory.newTransaction(NS, 'Offer');
lowOffer.member = factory.newRelationship(NS, 'Member', buyer2.$identifier);
lowOffer.listing = factory.newRelationship(NS, 'VehicleListing', 'LISTING_001');
lowOffer.bidPrice = 50;
await businessNetworkConnection.submitTransaction(lowOffer);
// get the listing
let newListing = await vehicleListingRegistry.get(listing.$identifier);
// both offers should have been added to the listing
newListing.offers.length.should.equal(2);
// close the bidding
const closeBidding = factory.newTransaction(NS, 'CloseBidding');
closeBidding.listing = factory.newRelationship(NS, 'VehicleListing', 'LISTING_001');
await businessNetworkConnection.submitTransaction(closeBidding);
// get the listing
newListing = await vehicleListingRegistry.get(listing.$identifier);
// the offer should have been added to the listing
newListing.state.should.equal('SOLD');
// get the buyer and seller
const theBuyer = await userRegistry.get(buyer.$identifier);
const theSeller = await userRegistry.get(seller.$identifier);
// check the buyer's balance
theBuyer.balance.should.equal(800);
// check the seller's balance
theSeller.balance.should.equal(200);
// get the vehicle
const theVehicle = await vehicleRegistry.get(vehicle.$identifier);
// check that the buyer now owns the car
theVehicle.owner.getIdentifier().should.equal(buyer.$identifier);
});
describe('#closeBidding', () => {
it('with no bids should result in RESERVE_NOT_MET', async () => {
const factory = businessNetworkConnection.getBusinessNetwork().getFactory();
const seller = factory.newResource(NS, 'Member', 'daniel.selman#example.com');
seller.firstName = 'Dan';
seller.lastName = 'Selman';
seller.balance = 0;
// create the vehicle
const vehicle = factory.newResource(NS, 'Vehicle', 'CAR_001');
vehicle.owner = factory.newRelationship(NS, 'Member', seller.$identifier);
// create the vehicle listing
const listing = factory.newResource(NS, 'VehicleListing', 'LISTING_001');
listing.reservePrice = 100;
listing.description = 'My nice car';
listing.state = 'FOR_SALE';
listing.vehicle = factory.newRelationship(NS, 'Vehicle', vehicle.$identifier);
// Get the registries.
const vehicleRegistry = await businessNetworkConnection.getAssetRegistry(NS + '.Vehicle');
const vehicleListingRegistry = await businessNetworkConnection.getAssetRegistry(NS + '.VehicleListing');
const userRegistry = await businessNetworkConnection.getParticipantRegistry(NS + '.Member');
// Add the Vehicle to the asset registry.
await vehicleRegistry.add(vehicle);
// add the seller to the member registry
await userRegistry.add(seller);
// add the vehicle listing
await vehicleListingRegistry.add(listing);
// close the bidding
const closeBidding = factory.newTransaction(NS, 'CloseBidding');
closeBidding.listing = factory.newRelationship(NS, 'VehicleListing', listing.$identifier);
await businessNetworkConnection.submitTransaction(closeBidding);
// get the listing and check state
const vehicleListing = await vehicleListingRegistry.get(listing.$identifier);
vehicleListing.state.should.equal('RESERVE_NOT_MET');
});
});
});
});
You can't use require in a hyperledger composer business network implementation as you see you get an error because the require keyword is not available.
If you want to learn about blockchain technology then you should not use hyperledger composer because it isn't a blockchain technology. Hyperledger Fabric is a blockchain technology and that would be far more worthwhile investing time to understand.
Hyperledger composer was a framework for business networks that could use hyperledger fabric blockchain technology to provide the persistence, immutability etc of the information that it wanted to store

Mongoose find with multiple and optional fields

I am new to mongoose and currently I am coding an app to learn it. I have an Artist Schema and a form that search with multiple and optional fields. For instance the user can put a name, a minimum age and search through the model without filling the other form fields.
On the controller I take all the fields from the form through the req.body object and I have a query object which with multiple if statements I check whether or not the property is not undefined, and if not I put it in the object as a property and the object is passed to the find method.
The problem is when I fill the min age and put to the query object this property query.min_age = { $gte: min_age} the $gte converts into a string and as a result can't run the find method properly.
The Mongoose Model
const mongoose = require("mongoose");
const AlbumSchema = require("./album")
const CompanySchema = require("./company")
const Schema = mongoose.Schema;
const ArtistSchema = new Schema({
name: String,
age: Number,
yearsActive: Number,
albums: [AlbumSchema],
company:[{type: Schema.Types.ObjectId, ref: "Company"}]
});
const Artist = mongoose.model("artist", ArtistSchema);
module.exports = Artist;
The Controller
app.post("/", (req, res, next) => {
const name = req.body.name;
const min_age = req.body.min_age;
const min_active = req.body.min_active;
const sort = req.body.sort;
const query = {};
if(name) {
query.name = name;
}
if(min_age) {
query.min_age = { $gte: min_age};
}
if(min_active) {
qyery.min_active = {gte: min_active};
}
Artist.find(query).
sort(sort)
.then( artists => {
res.render("index", {
artists: artists
})
});
});
The image below is depicting the string $gte when I console it:
Keys in JS objects are always casted to a string, so there is nothing wrong with $gte being a string on a screenshot that you've posted.
As for the min_age value, in your code I cannot see anything that would convert it to a string and mongoose by itself is not doing it as well.
It looks like the problem is in a test request. Please check if you are sending min_age as a number in a POST request, or as a string. It should be a number or else you need to convert it to a number in your controller (with parseInt() for example)
const name = new RegExp(req.body.name, 'i');
const min_age = req.body.min_age;
const min_active = req.body.min_active;
const sort = req.body.sort;
const query = {};
if(req.body.name!=undefined && req.body.name!=''){
query["$and"]=[{name :re}]
}
if(min_age){
query["$and"].push({min_age:{ $gte: parseInt(min_age)}})
}
if(min_active ){
query["$and"].push({min_active:{ $gte: parseInt(min_active)}})
}
let artists=await Artist.find(query).sort(sort)
res.render("index", {
artists: artists
})

How can I use equalTo for setting data(not finding data) javascript (Parse Platform)

Can we use equalTo for set data in database (not find data) in parse platform ?
It's not on documents
No. The equalTo() function only exists in Parse.Query instances for searching data. In order to set data, you need to use the set() function existent in Parse.Object instances. It would be something like the code below:
Updating a Single Object
const GameScore = Parse.Object.extend('GameScore');
const query = new Parse.Query(GameScore);
const gameScore = await query.get('xWMyZ4YEGZ');
gameScore.set('score', 1337);
gameScore.set('playerName', 'Sean Plott');
gameScore.set('cheatMode', false);
gameScore.set('skills', ['pwnage', 'flying']);
await gameScore.save();
Updating Multiple Objects
const GameScore = Parse.Object.extend('GameScore');
const query = new Parse.Query(GameScore);
query.equalTo('skills', 'flying');
const gameScores = await query.find();
gameScores.forEach(gameScore => {
gameScore.set('score', 1337);
gameScore.set('playerName', 'Sean Plott');
gameScore.set('cheatMode', false);
gameScore.set('skills', ['pwnage', 'flying']);
});
await Parse.Object.saveAll(gameScores);
You can find more information about how to find and save objects here
Using The code example you can also save like this:
(https://parseplatform.org/Parse-SDK-JS/api/master/Parse.Object.html#save)
const GameScore = Parse.Object.extend('GameScore');
const query = new Parse.Query(GameScore);
const gameScore = await query.get('xWMyZ4YEGZ');
await gameScore.save({
score: 1337,
playerName: 'Sean Plott',
cheatMode: false,
skills: ['pwnage', 'flying'],
});

Categories

Resources